NOIP2021 部分题目整理

(在 NOIP2022 前夕整理 NOIP2021。)

(真的太逊了。)

P7960 报数 Number

解法

由于题目中的因数的限制,考虑埃式筛。在埃式筛中如果遇到某个尚未被标记为非法的数时,如果该数本身包含 7,则需要对其所有倍数标记为非法。由于每个数最多不会被标记超过 5 次(7×17×27×37×47×57>3×108),故整个过程时间复杂度很小,可以说是小常数的 O(xlogx)时间复杂度为 O(xlogx) 的证明)。

代码

点此查看代码
#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(S30×212),可得 50 分。

考虑从 v0 考虑到 vm,将 202m 依次加入 S。在考虑到 vi 时,我们就只需要关心 Smod2i 有多少个 1,与 S/2i 的值(涉及到进位等内容)。

注意 {ai} 不一定是非降的。

推式子可得如下结论:

dpi,j,k,p 表示考虑到 vi (可以把这一维用滚动数组的方式优化成 2),使用了 j 个数,Smod2ik1S/2ipq=1ivaq,则转移有

dpi,j+c,k+pmod2,p2+c +=dpi1,j,k,p(cj+c)vic

时间复杂度:O(n4m),可以通过此题。

代码

醒醒大清无了

点此查看代码
#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

解法

考虑在将 ai 变为 ai1+ai+1ai 之后的影响:(ai1+ai+1ai)ai1=ai+1ai,ai+1(ai1+ai+1ai)=aiai1,相当于交换了 i+1i 处的差分。记 di=aiai1,则 d2dn 在这些操作后可以任意排列。

此时对于某个平均数 S,如果某两个数 ai,ai+1 均小于 Sdi+1>di,则将 di,di+1 交换后 ai 值会变大但不超过 ai+1ai 将会更接近 S,方差会更小。故最后的 d 一定会呈现单谷。

定义 S=j=1naj,则原式可以简化如下:

n2D=ni=1n(aiSn)2=ni=1n(ai22aiSn+S2n2)=ni=1nai22S(i=1nai)+S2=ni=1nai2S2

考虑从单谷部分开始向两边 dp,设 dpi,j 为考虑了前 i 个差分,且当前 a 值之和为 j 时所有 a 的平方和最小值。此时对每个 a 值均减去 a1 不会对答案造成影响,可以设 a1=0,也就是初值为 dp1,0=0,i0,dp1,i=+。转移时,如果新的 di 放在最左端,则其将其他每个 a 值均增加了 di,新的 a 值也是 di;如果新的 di 放在最右端,则这个新增的 a 值为 j=2idj,而其他 a 值不会被影响。设 si=j=2idj,则转移有:

dpi,j+diimin(dpi,j+dii,dpi1,j+2dij+di2(i1))dpi,j+simin(dpi,j+si,dpi1,j+si2)

第一维可以使用背包的类似优化方式优化掉。考虑 di=0 时一定有 si=0,转移只会有 dpi,j=min(dpi,j,dpi1,j),则可以把 di=0 的部分跳过,则最后有用的 d 值只会有 min(n,a) 个,故优化后的时间复杂度为 O(min(n,a)na)

代码

正解甚至比 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

解法(暂缺)

代码(暂缺)

点此查看代码
posted @   Fran-Cen  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示