• bzoj1025题解


    【题意分析】

      定义一个等价类为满足如下条件的一个极大的集合Q:∀t∈Q,k∈N+,若tk∈全集R,都成立tk∈Q。

      给定n,记[1,n]∩N上所有排列置换的全集为R。求对于所有的等价类Q,card({x|x=card(Q),Q∈R})。

    【解题思路】

      很明显,一个排列置换能分解成一个或几个不相交的置换环,其所在等价类的元素个数即为所有置换环长度的最小公倍数。

      显然,若一个置换所有置换环长度的最大公约数大于1,则一定有一个置换环长度的最大公约数等于1的所在等价类元素个数与之相同。

      所以,我们只要统计只有互质且不等于1的长度的置换环的置换所在等价类元素个数即可。

      这样问题就可以转化为如何拆分n使所有拆分出的数都是pk(p为互不相等的质数,k∈[1,+∞)∩N)。

      先筛出[1,n]∩N范围内所有质数,然后DP,f[i][j]表示已经选到了第i个质数,可分配的长度还剩下j的剩余时的拆分数。

      转移方程:f[i][j]=f[i-1][j]+Σf[i-1][j+p[i]k],时间复杂度O(nπ(n))。

    【参考代码】

     1 #pragma GCC optimize(2)
     2 #pragma comment(linker,"/STACK:1024000000,1024000000")
     3 #include <cstdio>
     4 #include <cstring>
     5 #define REP(i,low,high) for(register int i=(low);i<=(high);++i)
     6 using namespace std;
     7  
     8 static int n,cnt=0; long long f[1010][1010]; bool isprime[1010]; int prime[1010];
     9  
    10 long long DFS(const int &now,const int &rest)
    11 {
    12     if(now>cnt) return 1; if(~f[now][rest]) return f[now][rest];
    13     f[now][rest]=DFS(now+1,rest);
    14     for(register int i=prime[now];i<=rest;i*=prime[now])
    15     {
    16         f[now][rest]+=DFS(now+1,rest-i);
    17     }
    18     return f[now][rest];
    19 }
    20  
    21 int main()
    22 {
    23     scanf("%d",&n),memset(isprime,1,sizeof isprime),memset(f,-1,sizeof f);
    24     REP(i,2,n) if(isprime[i]) {REP(j,2,n/i) isprime[i*j]=0; prime[++cnt]=i;}
    25     return printf("%lld
    ",DFS(1,n)),0;
    26 }
    View Code
    We Secure, We Contain, We Protect.
  • 相关阅读:
    raspi扩展板
    树莓派学习笔记——I2C设备载入和速率设置
    python多线程(四)
    python多线程(三)
    python多线程(二)
    python3.x对python2.x变动
    python多线程(一)
    raspi集成库及安装
    eclipse软件安装及python工程建立
    原型模式
  • 原文地址:https://www.cnblogs.com/spactim/p/6492328.html
Copyright © 2020-2023  润新知