BZOJ 1025 游戏【置换群】

来源:互联网 发布:多肉植物淘宝店推荐 编辑:程序博客网 时间:2024/06/06 12:36

【题意】略,中文题可自己查看!

【分析】在做题之前介绍一下置换群的基本概念。。。置换的概念是什么?一个有限集合的一一变换叫做置换,一对对置换组成了置换群。对于一个集合a(a[1],a[2],a[3]...a[n]) 通过置换可以变成 (b[a[1]],b[a[2]],b[a[3]]...b[a[n]]) b的作用就是置换(可以理解为某种函数的作用),将原来的集合映射成具有相应次序的集合a',a'可以看做是a的相同元素集合,不同的排列组合的一个集合。 每个n元的置换都可以表示成若干个互不相交的循环置换的乘积,设每个子循环置换的循环节为ci,则总的置换的循环节显然为lcm(c1,c2..cn)

好了,那么这个题一眼就可以看出是典型的置换群了。顾而

=lcm{Ai,Ai},i=1kAi=n
因此这个问题转化为了,把一个数n拆分成若干个数,问这若干个数的最小公倍数的可能情况数!计数问题,典型的dp转移!

【状态表示】

筛素数表,dp[i][j]表示j拆分的若干个数分解质因数之后最大质因数不超过第i个质因数的最小公倍数可能性。

dp[i][j]=dp[i-1][j]+sigma{dp[i][j-p[i]^k]}

[AC代码]

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;#define ll long longbool used[1005];int prime[1005];int num,n;ll dp[1005][1005];//i个质数和为j的总方案数void make_tab(int x){    memset(used,false,sizeof(used));    for(int i=2; i<=x; i++)    {        if(!used[i])        {            prime[++num]=i;            for(int j=i*i; j<=x; j+=i)            {                used[j] = true;            }        }    }}void solve(){    dp[0][0]=1;    for(int i=1; i<=num; i++)    {        for(int j=0; j<=n; j++)        {            dp[i][j] = dp[i-1][j];        }        for(int j=prime[i]; j<=n; j*=prime[i])        {            for(int k=0; k<=n-j; k++)            {                dp[i][j+k]+=dp[i-1][k];            }        }    }    ll ans = 0;    for(int i=0; i<=n; i++)    {        ans+=dp[num][i];    }    cout<<ans<<endl;}int main(){    cin>>n;    make_tab(n);    solve();    return 0;}



  

因此

1 0
原创粉丝点击