NOIP2021比赛题解

报数

1.禁止报的数的生成规则与埃氏筛法类似,考虑用筛法预处理可以报出的数字列表和不可报出的数字,从而 O(1) 回答每一组询问。

具体来说,从 1 开始逐一处理每个正整数。当处理到数字 x 时,如果数字 x 尚未被标记为不合法,就通过拆位判断它是否合法。如果是合法数字,则将其加入合法数字列表,否则将 x 的所有倍数(包括 x 本身)全部标记为不合法数字;如果数字 x 已经被标记为不合法,则因为数字 x 的所有倍数都已经在之前和数字 x 一同被标为不合法数字,不需要再执行额外操作。

2.The end...

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int t,la,nx[N];
bool f[N];
bool check(int x){
	while(x!=0){
		if(x%10==7) return 1;
		x/=10;
	}
	return 0;
}
void pre(){
	for(int i=1;i<=N;i++){
		if(f[i]) continue;
		if(check(i)){
			for(int j=1;i*j<=N;j++){
				f[i*j]=1;
			}
			continue;
		}
		nx[la]=i;
		la=i;
	}
	return;
}
int main(){
	scanf("%d",&t);
	pre();
	while(t--){
		int x;
		scanf("%d",&x);
		if(f[x]) printf("-1\n");
		else printf("%d\n",nx[x]);
	}
	return 0;
}

数列

1.可以想到dp。可以发现,S 的二进制表示位中 1 的数量会涉及进位的问题。由于进位是从低位向高位进行的,所以考虑在 S 中从低位到高位按位 dp(最低位为第 0 位)。

2.设计 dp 状态 f(i,j,k,p) 表示:讨论了 S 从低到高的前 i 位,已经确定了 j 个序列 a 中的元素,S 从低到高前 i 位中有 k 个 1,要向当前讨论位的下一位进位 p。因为从上一个状态转移到 f(i,j,k,p) 细节太多,所以考虑用 f(i,j,k,p) 往后转移。接下来讨论第 i 位(位从 0 开始编号)。假设序列 a 中有 t 个元素为 i,那么就相当于给 S 的第 i 位贡献了 t 个 1,再加上上一位进过来的 p 个 1,总共有 t+p 个 1。可以知道,当前位每两个 1 可以向下一位进 1。所以 (t+p)%2 的结果即为全部进位后当前位是否为 1。同理,向下一位进的 1 的个数即为 ⌊t+p2⌋/2。

f(i,j,k,p) 往后转移的状态为f(i+1,j+t,k+(t+p)%2,⌊2t+p​⌋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值