【补题计划】NOIP 2021
【NOIP 2021】补题记录
前言
听说Eafoo最近在搞真题,正好闲来无事(其实没有啦),也开始我的补题计划
T1 【NOIP 2021】报数
签到题qwq
不过也没见过这么水的签到题
就是筛啦
还有就是筛的时候不要卡在1e7,要开大点(1e7+5)
AC code
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=1e7;
inline int read()
{
int w=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
f=-1;
}
ch=getchar();
}
while(ch>='0' && ch<='9')
{
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w*f;
}
int T;
int las;
int nex[maxn];
bool sign[maxn];
bool check(int x)
{
if(x==7)
{
return false;
}
while(x)
{
if(x%10==7)
{
return false;
}
x/=10;
}
return true;
}
signed main()
{
T=read();
for(int i=1;i<=maxn+5;i++)
{
if(sign[i])
{
continue;
}
if(!check(i))
{
sign[i]=true;
for(int j=i;j<=maxn+5;j+=i)
{
sign[j]=true;
}
continue;
}
nex[las]=i;
las=i;
}
while(T--)
{
int k=read();
if(sign[k])
{
cout<<-1<<endl;
continue;
}
cout<<nex[k]<<endl;
}
return 0;
}
T2 【NOIP 2021】数列
一看就是计数DP题,还是关于数位&组合数的
记得EB学长AFO前告诉我要把这题切了
看数据范围不是高维DP就是状压DP,而我们好像没什么可压得
那就搞高维DP
就是在二进制数位上进行转移
DP[i][j][k][l]表示搞了i个数,现在的最高位是j(也就是现在在考虑的这一位),要进k位,现在发现有l个1
然后发现好像不好从之前的状态往现在的状态转移
那我们就从现在向之后的状态转移
设当前这一位要填num个j
dp[i+num][j+1][(k+num)>>1][l+((k+num)&1)]+=dp[i][j][k][l] * c[i+num][num] * val[j][num];
涉及到进位就很烦啦。。。
转移一定要多取几个% 而且要预处理组合数&val的次方
AC code
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
const int N=35;
const int maxn=110;
const int mod=998244353;
inline int read()
{
int w=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
f=-1;
}
ch=getchar();
}
while(ch>='0' && ch<='9')
{
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w*f;
}
int n,m,lim;
int val[maxn];
int c[maxn][maxn];
int v[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];
int count_one(int x)
{
int cnt=0;
for(;x;x>>=1)
{
if(x&1)
{
cnt++;
}
}
return cnt;
}
signed main()
{
n=read();
m=read();
lim=read();
for(int i=0;i<=m;i++)
{
val[i]=read();
val[i]%=mod;
}
c[0][0]=1;
for(int i=1;i<N;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
for(int i=0;i<=m;i++)
{
v[i][0]=1;
for(int j=1;j<=n;j++)
{
v[i][j]=(val[i]*v[i][j-1])%mod;
}
}
dp[0][0][0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=i/2;k++)
for(int l=0;l<=lim;l++)
if(dp[i][j][k][l])
for(int num=0;num<=n-i;num++)
dp[i+num][j+1][(k+num)>>1][l+((k+num)&1)]=(dp[i+num][j+1][(k+num)>>1][l+((k+num)&1)]+dp[i][j][k][l]*v[j][num]%mod*c[i+num][num]%mod)%mod;
int ans=0;
for(int k=0;k<=n;k++)
for(int l=0;l<=lim;l++)
if(count_one(k)+l<=lim)
ans=(ans+dp[n][m+1][k][l])%mod;
cout<<ans%mod;
return 0;
}
T3 【NOIP 2021】方差
又是DP(去年NOIP考了两道DP,CSP-S一道DP)
需要自己推一下性质
操作就是将i与i+1的差分数组换了一下
而且最优情况应该是单谷的(有dalao推出了式子,不过大多数人都是手模样例或者暴力打表猜出来的)
我们可以将差分数组从小到大sort
式子可以转化为\(n*\sum a^{2}-(\sum a)^{2}\)
dp[i][j]表示前i个差分后\(\sum a\)为j时\(\sum a^{2}\)的min值
因为是单谷的所以转移时就是考虑这一次要放到左面还是右面
看起来会T,然是实际上有许多冗余产生
那就是dif==0的情况
continue就好啦
AC code
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<climits>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=1e4+10;
const int INF=1e18;
inline int read()
{
int w=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
f=-1;
}
ch=getchar();
}
while(ch>='0' && ch<='9')
{
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w*f;
}
int n;
int a[maxn];
int dif[maxn];
int sum[maxn];
int dp[2][maxn*60];
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
}
for(int i=1;i<n;i++)
{
dif[i]=a[i+1]-a[i];
}
sort(dif+1,dif+n);
for(int i=1;i<n;i++)
{
sum[i]=sum[i-1]+dif[i];
}
int maxm=a[n];
for(int i=1;i<=maxm*n;i++)
{
dp[0][i]=INF;
dp[1][i]=INF;
}
dp[1][0]=0;
for(int i=1;i<n;i++)
{
if(dif[i]==0) continue;
for(int j=0;j<=maxm*n;j++)
{
dp[i&1][j]=INF;
}
for(int j=0;j<=maxm*n;j++)
{
if(dp[~i&1][j]==INF) continue;
dp[i&1][j+sum[i]]=min(dp[i&1][j+sum[i]],dp[~i&1][j]+sum[i]*sum[i]);
dp[i&1][j+dif[i]*i]=min(dp[i&1][j+dif[i]*i],dp[~i&1][j]+i*dif[i]*dif[i]+2*j*dif[i]);
}
}
int ans=INF;
for(int i=0;i<=maxm*(n-1);i++)
{
if(dp[~n&1][i]!=INF)
{
ans=min(ans,n*dp[~n&1][i]-i*i);
}
}
cout<<ans;
return 0;
}
T4 【NOIP 2021】棋局
我超,黑的
算了吧还是(对自己的定位非常清楚)