BZOJ1025(SCOI2009)[游戏]--线性筛+DP

来源:互联网 发布:等一分钟网络女歌手 编辑:程序博客网 时间:2024/06/08 06:51

【链接】
bzoj1025

【解题报告】

对于a变换到b,可以看成a指向b的一条路径。

易知每个点的出度,入度都为1。

所以会存在点数大于等于1环,或是路径只有a->a的形式。

所以题目就变为求这几个环大小的最小公倍数的方案数了。

所以我们可以用筛法筛出小于等于n的素数,再进行DP就行了。

#include<cstdio>#include<cstring>#define LL long longusing namespace std;const int maxn=1005;int n,cnt,p[maxn];LL ans,f[maxn][maxn];bool vis[maxn];void Getpre(){    memset(vis,0,sizeof(vis)); cnt=0;    for (int i=2; i<=n; i++)    {        if (!vis[i]) p[++cnt]=i;        for (int j=1; j<=cnt&&i*p[j]<=n; j++)        {            vis[i*p[j]]=1;            if (i%p[j]==0) break;        }    }}int main(){    freopen("1025.in","r",stdin);    freopen("1025.out","w",stdout);    scanf("%d",&n); Getpre();    memset(f,0,sizeof(f));    ans=0; f[0][0]=1;    for (int i=1; i<=cnt; i++)    {        for (int j=0; j<=n; j++) f[i][j]=f[i-1][j];        for (int j=p[i]; j<=n; j*=p[i])         for (int k=j; k<=n; k++)          f[i][k]+=f[i-1][k-j];    }    for (int i=0; i<=n; i++) ans+=f[cnt][i];    printf("%lld",ans);    return 0;}
原创粉丝点击