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;
}
标签:ch,P5746,int,res,机器人,素数,NOI2002,编号,dp 来源: https://www.cnblogs.com/Akmaey/p/15169748.html