NOIP2021 部分题目整理
(在 NOIP2022 前夕整理 NOIP2021。)
(真的太逊了。)
P7960 报数 Number
解法
由于题目中的因数的限制,考虑埃式筛。在埃式筛中如果遇到某个尚未被标记为非法的数时,如果该数本身包含 ,则需要对其所有倍数标记为非法。由于每个数最多不会被标记超过 次(),故整个过程时间复杂度很小,可以说是小常数的 (时间复杂度为 的证明)。
代码
点此查看代码
#include <bits/stdc++.h> using namespace std; const int maxn=10001000; inline bool p(int x){ while(x){ if(x%10==7) return 1; x/=10; } return 0; } int n,i,j,l; int nxt[maxn]; int main(){ for(i=1;i<maxn;++i){ if(nxt[i]) continue; if(p(i)) for(j=i;j<maxn;j+=i) nxt[j]=-1; if(!nxt[i]) l=nxt[l]=i; } scanf("%d",&n); while(n--){ scanf("%d",&l); printf("%d\n",nxt[l]); } return 0; }
P7961 数列 Sequence
解法
直接状压 dp(),可得 分。
考虑从 考虑到 ,将 依次加入 。在考虑到 时,我们就只需要关心 有多少个 ,与 的值(涉及到进位等内容)。
注意 不一定是非降的。
推式子可得如下结论:
设 表示考虑到 (可以把这一维用滚动数组的方式优化成 ),使用了 个数, 有 个 , 为 的 ,则转移有
时间复杂度:,可以通过此题。
代码
醒醒大清无了
点此查看代码
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn=40; const int maxm=100; const ll md=998244353; int n,m,k,i,j,p,q,r,s; bool x,y=1; ll v,cf,tmp,C[maxn][maxn]; ll dp[2][maxn][maxm][maxn]; inline void Add(ll &_x,const ll _y){ _x+=_y; if(_x>=md) _x%=md; } int main(){ freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); C[0][0]=1; for(i=1;i<maxn;++i){ for(j=0;j<=i;++j){ Add(C[j][i],C[j][i-1]+C[j-1][i-1]); } } scanf("%d%d%d",&n,&m,&k); dp[0][0][0][0]=1; for(i=0;i<=m;++i){ scanf("%lld",&v); for(r=0;r<=n;++r){ cf=1; for(p=0;p<=r;++p){ for(j=0;j<maxm;++j){ s=j&1; for(q=0;q<=k;++q){ tmp=dp[x][r-p][j][q]*cf; if(tmp>=md) tmp%=md; Add(dp[y][r][(j>>1)+p][s],tmp*C[p][r]); if((++s)>k) break; } } cf*=v; if(cf>=md) cf%=md; } } memset(dp[x],0,sizeof(dp[x])); swap(x,y); } tmp=0; for(i=0;i<maxm;++i){ if(!i) s=0; else s=__builtin_popcount(i); for(j=0;j<=k;++j){ if(s>k) break; Add(tmp,dp[x][n][i][j]); ++s; } } printf("%lld",tmp); return 0; }
P7962 方差 Variance
解法
考虑在将 变为 之后的影响:,相当于交换了 和 处的差分。记 ,则 在这些操作后可以任意排列。
此时对于某个平均数 ,如果某两个数 均小于 且 ,则将 交换后 值会变大但不超过 , 将会更接近 ,方差会更小。故最后的 一定会呈现单谷。
定义 ,则原式可以简化如下:
考虑从单谷部分开始向两边 dp,设 为考虑了前 个差分,且当前 值之和为 时所有 的平方和最小值。此时对每个 值均减去 不会对答案造成影响,可以设 ,也就是初值为 。转移时,如果新的 放在最左端,则其将其他每个 值均增加了 ,新的 值也是 ;如果新的 放在最右端,则这个新增的 值为 ,而其他 值不会被影响。设 ,则转移有:
第一维可以使用背包的类似优化方式优化掉。考虑 时一定有 ,转移只会有 ,则可以把 的部分跳过,则最后有用的 值只会有 个,故优化后的时间复杂度为 。
代码
正解甚至比 8 pts 暴力短()
点此查看代码
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn=10010; const int maxv=500010; int n,i,j,s,v,d[maxn]; ll a=1e14,dp[maxv]; inline void cmin(ll &x,ll y){if(y<x) x=y;} int main(){ freopen("variance.in","r",stdin); freopen("variance.out","w",stdout); scanf("%d",&n); for(i=1;i<=n;++i) scanf("%d",d+i); for(i=n;i;--i) d[i]-=d[i-1]; for(j=0;j<maxv;++j) dp[j]=1e14; sort(d+2,d+n+1); dp[0]=0; if(!d[n]){printf("0\n");return 0;} for(i=2;i<=n;++i){ if(!(s+=d[i])) continue; v=(i-1)*d[i]; for(j=maxv-1;~j;--j){ if(j<maxv-v) cmin(dp[j+v],dp[j]+1LL*d[i]*v+2*d[i]*j); if(j<maxv-s) cmin(dp[j+s],dp[j]+s*s); dp[j]=1e14; } } for(j=1;j<maxv;++j) a=min(a,dp[j]*n-1LL*j*j); printf("%lld",a); return 0; }
P7963 棋局 Chess
解法(暂缺)
代码(暂缺)
点此查看代码
本文来自博客园,作者:Fran-Cen,转载请注明原文链接:https://www.cnblogs.com/Fran-CENSORED-Cwoi/p/16911654.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?