【补题计划】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】棋局

我超,黑的

算了吧还是(对自己的定位非常清楚)

posted @ 2022-09-24 18:33  NinT_W  阅读(53)  评论(2编辑  收藏  举报