作业介绍
2026年编程兔冬令营集训第一场作业
1、素数处理
2、深度搜索
3、动态规划
1、埃式筛法
#include<bits/stdc++.h>
using namespace std;
bool isPrime[100000005];
int main(){
long long i,j,n,m,ans=0;
cin>>n;
if(n>=2) {
ans=1;
for(i=3;i<=n;i+=2) if (!isPrime[i]){ //优化从3开始
ans++;
for(j=i*i;j<=n;j+=i) isPrime[j] = true;
}
}
cout<<ans<<endl;
return 0;
}
2、埃式筛法
#include<bits/stdc++.h>
using namespace std;
bool isPrime[100005];
int main(){
int n,ans =0,t=0;
cin>>n;
for(long long i=2;i<=n;++i){
if (isPrime[i]){
++t; //非素数累计
ans = max(ans,t);//记录答案最大值
}else{
t=0; //碰到素数,累计清零
// 注意i*i的范围
for(long long j=i*i;j<=n;j+=i) isPrime[j] = 1;
}
}
cout<<ans<<endl;
return 0;
}
3、单点对单点dfs。按照题目的要求按照左、上、右、下顺序进行搜索,需要找第一条出路,所有使用DFS。
优化走过的点进行标志,避免重复走过。
#include <iostream>
using namespace std;
char a[25][25];//存贮地图
int r[405][3];//存贮路径
int n;
void show(int k){
for(int i = 1;i < k;i++)
cout<<"("<<r[i][1]<<","<<r[i][2]<<")->";
cout<<"("<<r[k][1]<<","<<r[k][2]<<")"<<endl;
}
//从x、y点开始逐步探测
void dfs(int x,int y,int k){
r[k][1] = x; r[k][2] = y;
a[x][y] = '1';//探测过的点,设置为不可探测,防止重复的探测
if(x == n && y == n) show(k);// 找到出路,进行打印
}else{
//左、上、右、下探测,且不越界
if(y - 1 >= 1 && a[x][y - 1] == '0') dfs(x,y - 1,k+1);
if(x - 1 >= 1 && a[x - 1][y] == '0') dfs(x-1,y,k+1);
if(y + 1 <= n && a[x][y + 1] == '0') dfs(x,y + 1,k+1);
if(x + 1 <= n && a[x + 1][y] == '0') dfs(x+1,y,k+1);
}
}
int main(){
cin>>n;
//0表示能走,1表示不能走
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
cin>>a[i][j];
dfs(1,1,1);
return 0;
}
4、单点对多点dfs。
#include<bits/stdc++.h>
using namespace std;
bool a[110][110];
bool flag[110];
int n,e;
void init()
{
cin>>n>>e;
memset(flag,0,sizeof(flag));
memset(a,0,sizeof(a));
int x,y;
for(int i=1;i<=e;++i)
{
cin>>x>>y;
a[x][y]=1;//无向图处理双向
a[y][x]=1;
}
}
void dfs(int x)
{
cout<<x<<' ';
flag[x]=1;//把遍历点设为已访问
for(int i=1;i<=n;++i) //寻找相邻连通的下一个节点
if(!flag[i]&&a[x][i]==1) dfs(i);//如果找到以这个节点接着遍历
}
int main()
{
init();
dfs(1);
return 0;
}
5、这道题跟大家期末测试的“上楼梯”很像。复习一下“上楼梯”的递归公式
dp[i] = dp[i-1]+dp[i-2];
上面的题是求方案总数,新的题是求总的最大值/最小值。
dp[i] = dp[i]+max(dp[i-1],dp[i-2]);
#include<bits/stdc++.h>
using namespace std;
int dp[100010],n,A,B,C;
int main(){
cin>>n>>A>>B>>C;
for (int i = 1; i <= n; i++){
int tmp = ((long long)A * i * i + B * i + C) % 20000;
dp[i] = tmp - 10000;
}
for (int i = 2; i <= n+1; i++){
dp[i] = max(dp[i-1],dp[i-2]) + dp[i];
}
cout<<dp[n+1];
return 0;
}
6、背包问题dp,暴力(2^n),dp(V*n)
#include<bits/stdc++.h>
using namespace std;
int V,n,ans;
int a[31];
int dp[20005]={0};
int main ()
{
int i,j;
cin>>V>>n;
ans = 0;
for(i=0;i<n;i++) cin>>a[i];
for(i=0;i<n;i++) if (a[i]<=V)
{
//如果前面的物品能凑出j的体积,则加上a[i]后能凑出j+a[i]的体积
//注意j从大到小
for(j=V-a[i];j>0;j--) if (dp[j])
{
dp[j+a[i]] =1;
ans = max(ans, j+a[i]);
}
dp[a[i]] =1;
ans = max(ans, a[i]);
}
cout<<V-ans<<endl;
return 0;
}
7、也是类背包问题,用暴力枚举可以通过40分(2^n)。
假设dp[x][y]表示x条边可以组成长度为y的方案数。
对边进行排序,对于每一条边a[i]有选或者不选进行出路。dp[x][y]的公式有
x=3->x>3的情况,有dp[3][y+a[i]]+=dp[3][y];
x=2->x=3的情况,有dp[3][y+a[i]]+=dp[2][y];
x=1->x=2的情况,有dp[2][y+a[i]]+=dp[1][y];
x=0->x=1的情况,有dp[1][a[i]]++;
#include<bits/stdc++.h>
using namespace std;
long long V,n,ans=0,mod = 998244353;
int a[5005];
long long dp[4][5005]={0};
int main ()
{
int i,j,t,sum=0;
cin>>n;
ans = 0;
for(i=0;i<n;i++) cin>>a[i];
//排序从小到大,方便后面处理前i个的最大值是a[i]
sort(a,a+n);
for(i=0;i<n;i++)
{
for(j=min(5001,sum);j>=0;--j) {
t=min(5001,j+a[i]);
//边数已经>=3的
if (dp[3][j]>0){
if (j>a[i]) ans = (ans +dp[3][j]) % mod;
dp[3][t] = (dp[3][t]+dp[3][j]) % mod;
}
//边数已经=2的
if (dp[2][j]>0){
if (j>a[i]) ans = (ans +dp[2][j]) % mod;
dp[3][t] = (dp[3][t]+dp[2][j]) % mod;
}
//边数已经=1的
if (dp[1][j]>0) dp[2][t] = (dp[2][t]+dp[1][j]) % mod;
}
sum+=a[i];
//边数=1
dp[1][a[i]]++;
}
cout<<ans<<endl;
return 0;
}
题目
认领作业后才可以查看作业内容。
- 状态
- 正在进行…
- 题目
- 7
- 开始时间
- 2026-2-1 0:00
- 截止时间
- 2027-1-1 23:59
- 可延期
- 24 小时