P5746 [NOI2002] 机器人M号

题目

P5746 [NOI2002] 机器人M号

分析

这道题足以显示我 \(dp\) 水平真是菜到家了。。才做了不久又不会了。。

首先题目里面说:

对于编号为 \(m\) 的机器人,如果能把 \(m\) 分解成偶数个不同奇素数的积,则它是政客,例如编号 \(15\)

否则,如果 \(m\) 本身就是奇素数或者能把 \(m\) 分解成奇数个不同奇素数的积,则它是军人,例如编号 \(3\),编号 \(165\)

其它编号的机器人都是学者,例如编号 \(2\), 编号 \(6\), 编号 \(9\)

注意到不同奇素数,发现这样的数很少,但是我们还是没办法暴力,不过,因为要求不同,那么每一个数只有 选/不选 两种情况,这让我们想到了什么,\(dp\)

于是设状态 \(dp[i,0/1]\) 表示:前 \(i\) 个质因子可以构成的所有数当中,选了偶数个数/奇数个数的所有数的独立数之和。

根据当前这个质数选和不选两种情况,有转移方程:\(\large dp[i,v]=dp[i-1,v^1]\times \varphi{(prime[i])}+dp[i-1,v]\)

然后学者的人数就简单运用减法原理一下即可。

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=false;
    while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return ;
}
template <typename T>
inline void write(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10^48);
    return ;
}
const int N=1e6+5,M=1e6+5,MOD=10000;
#define ll long long
int n,p,c,dp[N][2];
inline int QuickPow(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=res*x%MOD;
		x=x*x%MOD;
		y>>=1;
	}
	return res;
}
int main(){
	read(n);int tmp=1;
	dp[0][0]=1;
	for(int i=1;i<=n;i++){
		read(p),read(c);
		tmp=tmp*QuickPow(p,c)%MOD;
		dp[i][0]=(dp[i-1][1]*(p==2?0:p-1)+dp[i-1][0])%MOD;
		dp[i][1]=(dp[i-1][0]*(p==2?0:p-1)+dp[i-1][1])%MOD;
	}
	dp[n][0]=(dp[n][0]-1+MOD)%MOD;
	write(dp[n][0]),putchar('\n'),write(dp[n][1]),putchar('\n'),write(((tmp-dp[n][0]-dp[n][1]-1)%MOD+MOD)%MOD);
	return 0;
}
posted @ 2021-08-21 15:51  __Anchor  阅读(158)  评论(0编辑  收藏  举报