zoukankan      html  css  js  c++  java
  • 组合基础小记

    一直不大喜欢写题解 尤其做的很纠结的题目 终于纠结完了 就想代码一贴完事。缺点一:理解不透彻;二:很容易忘;三:不利于以后回顾复习;四:写代码容易乱;

    以这个专题为开始吧 把一些题目总结一下 解释一下 同一类型的放在一块 。

    hdu1465 不容易系列之一 (错排公式)

    虽说大家知道 还是把这个小小说一下

    来自百度百科

    当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
    第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
    第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;
    综上得到
    D(n) = (n-1) [D(n-2) + D(n-1)]
     1 #include <iostream>
     2 #include<cstdio>
     3 #include<stdlib.h>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<vector>
     8 #include<queue>
     9 #include<stack>
    10 #include<set>
    11 using namespace std;
    12 #define LL long long
    13 LL f[22];
    14 int main()
    15 {
    16     int i,n;
    17     f[1] = 0;
    18     f[2] = 1;
    19     while(cin>>n)
    20     {
    21         for(i = 3; i <= n ; i++)
    22         f[i] = (i-1)*(f[i-1]+f[i-2]);
    23         cout<<f[n]<<endl;
    24     }
    25     return 0;
    26 }
    View Code

    poj1850 Code

    以前做过 没印象了。。

    仔细想一下 也是很简单的 一个字母的所有排列就是C(n,1),二个字母C(n,2),三个字母C(n,3)........依次

    具体的就类似于逐位了 注意下细节就OK了

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<stdlib.h>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<vector>
     8 #include<queue>
     9 #include<stack>
    10 #include<set>
    11 using namespace std;
    12 #define LL long long
    13 char s[12];
    14 LL c[30][15];
    15 void init()
    16 {
    17     int i,j;
    18     for(i = 0 ;i <= 26 ;i++)
    19     c[i][0] = 1;
    20     for(i = 1 ; i <= 26 ;i++)
    21         for(j = 1 ; j <= 10 ; j++)
    22         c[i][j] = c[i-1][j-1]+c[i-1][j];
    23 }
    24 int main()
    25 {
    26     int i,j,k;
    27     init();
    28     while(cin>>s)
    29     {
    30         k = strlen(s);
    31         if(k>1)
    32         {
    33              for(i = 0 ; i < k-1 ; i++)
    34             if(s[i+1]<s[i]) break;
    35             if(i!=k-1) {puts("0");continue;}
    36         }
    37         LL ans=0;
    38         for(i = 1 ; i < k ;i++)
    39         ans+=c[26][i];
    40         int t;
    41         for(i = 0; i < k ;i++)
    42         {
    43             if(i!=0)
    44             t = 'z'-s[i-1]-1;
    45             else
    46             t = 25;
    47             //cout<<'z'-s[i]+1<<endl;
    48             for(j = max(('z'-s[i]+1),k-i-1) ; j <= t ; j++)
    49             {
    50                 //cout<<j<<endl;
    51                 ans+=c[j][k-i-1];
    52             }
    53         }
    54         ans++;
    55         cout<<ans<<endl;
    56     }
    57     return 0;
    58 }
    View Code

    poj2773 Happy 2006  二分+容斥原理

    容斥原理可以明显的看的出 也算是模板题了

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 using namespace std;
    11 #define N 10000000000
    12 #define LL long long
    13 int p[32],g;
    14 LL sum=0;
    15 int gcd(int a,int b)
    16 {
    17     return b==0?a:gcd(b,a%b);
    18 }
    19 void dfs(int num,LL y,int i,LL n)
    20 {
    21     y = p[i]*y;
    22     if(num%2==0) sum-=n/y;
    23     else sum+=n/y;
    24     for(int j = i+1 ; j <= g ; j++)
    25     dfs(num+1,y,j,n);
    26 }
    27 int main()
    28 {
    29     int m,k,i;
    30     while(cin>>m>>k)
    31     {
    32         g = 0;
    33         for(i = 2; i <= m ;i++)
    34         {
    35             if(m%i==0) p[++g] = i;
    36             while(m%i==0)
    37             {
    38                 m/=i;
    39             }
    40         }
    41         if(m!=1) p[++g] = m;
    42         LL low = 1,high = N,mid;
    43         LL ans;
    44         while(low<=high)
    45         {
    46             mid = (low+high)/2;
    47             sum=0;
    48             for(i = 1; i <= g; i++)
    49             {
    50                 dfs(1,1,i,mid);
    51             }
    52             /*if(mid-sum==k)
    53             {
    54                 while(gcd(mid,k)!=1)mid--;
    55                 break;
    56             }*/
    57             if(mid-sum<k) low = mid+1;
    58             else {high = mid-1;}
    59         }
    60         cout<<low<<endl;
    61     }
    62     return 0;
    63 }
    View Code

    POJ 1091 跳蚤  容斥

    这跳骚很牛X 。。特别能跳  

    这个可以想到 可以跳出相差为一的 就是gcd(x1,x2,,....xn) = 1,具体我也不知道怎么证  我是以欧几里得猜的 ax+by = gcd(x,y) 有解

    这个题求补集 把每一次的减去

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100000
    12 #define LL __int64
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 int p[32];
    18 double ppow(int x,int n)
    19 {
    20     int i;
    21     double s = 1;
    22     for(i = 1; i <= n ;i++)
    23     s*=x;
    24     return s;
    25 }
    26 int main()
    27 {
    28     int i,j,n,m;
    29     scanf("%d%d",&n,&m);
    30     int g = 0;
    31     int q = m;
    32     for(i = 2 ; i*i <= m ;i++)
    33     {
    34         if(m%i==0) p[++g] = i;
    35         while(m%i==0)
    36         m/=i;
    37         if(i>m) break;
    38     }
    39     if(m!=1) p[++g] = m;
    40     double s = ppow(q*1.0,n);
    41     for(i = 1 ; i < (1<<g) ; i++)
    42     {
    43         int o = 0,y=1;
    44         for(j = 0 ; j < g ; j++)
    45         {
    46             if(i&(1<<j))
    47             {
    48                 o++;
    49                 y*=p[j+1];
    50             }
    51         }
    52         LL x = q/y;
    53         if(o%2) s-=ppow(x,n);
    54         else s+=ppow(x,n);
    55     }
    56     printf("%I64d
    ",(LL)s);
    57     return 0;
    58 }
    View Code

    HDU 1695 GCD   容斥

    这个其实把最大公约数除去之后 求一下互质的个数 可能数据有点水吧 直接枚举每一个的与其互质的个数 然后加起来 

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 #define LL __int64
    10 #define N 100010
    11 LL o[N];
    12 int p[22];
    13 LL init(int s1,int s2)
    14 {
    15     int i,j,e;
    16     LL cnt = 0;
    17     for(i = s1 ; i >= 2 ; i--)
    18     {
    19         int g = 0,x=i;
    20         for(j = 2 ; j*j <= x ; j++)
    21         {
    22             if(x%j==0){p[++g] = j;}
    23             while(x%j==0) x/=j;
    24         }
    25         if(x!=1) p[++g] = x;
    26         int ans = i+s2-s1;
    27         for(j = 1 ; j < (1<<g) ; j++)
    28         {
    29             int s = 0,y=1;
    30             for(e = 0 ; e < g ; e++)
    31             {
    32                 if(j&(1<<e))
    33                 {
    34                     s++;
    35                     y*=p[e+1];
    36                 }
    37             }
    38             if(s%2)
    39             {
    40                 ans-=i/y; ans-=(s2/y-s1/y);
    41             }
    42             else {ans+=i/y;ans+=(s2/y-s1/y);
    43             }
    44         }
    45         cnt += ans;
    46     }
    47     return cnt+s2-s1+1;
    48 }
    49 int main()
    50 {
    51     int k,a,b,c,d;
    52     int t,kk=0;
    53     cin>>t;
    54     while(t--)
    55     {
    56         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    57         if(b>d) swap(b,d);
    58         printf("Case %d: ",++kk);
    59         if(k==0||b<k)
    60         {
    61             cout<<"0
    ";
    62             continue;
    63         }
    64         cout<<init(b/k,d/k)<<endl;
    65     }
    66     return 0;
    67 }
    View Code

    HDU 2079  选课时间  普通型母函数

    直接套模板

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<stdlib.h>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 int k[10],o[10],num[10];
    10 int c1[55],c2[55];
    11 bool f[10];
    12 int main()
    13 {
    14     int i,j,a,b,n,k,t,e;
    15     cin>>t;
    16     while(t--)
    17     {
    18         memset(o,0,sizeof(o));
    19         memset(f,0,sizeof(f));
    20         memset(c1,0,sizeof(c1));
    21         memset(c2,0,sizeof(c2));
    22         cin>>n>>k;
    23         int g = 0;
    24         for(i = 1; i <= k ;i++)
    25         {
    26             cin>>a>>b;
    27             o[a]+=b;
    28             if(!f[b])
    29             {
    30                 num[++g] = a;
    31             }
    32         }
    33         for(i = 0 ; i <= num[1]*o[num[1]] &&i<=n; i += num[1])
    34         c1[i] = 1;
    35         for(i = 2 ; i <= g ;i++)
    36         {
    37             for(j = 0 ; j <= n ; j++)
    38             for(e = 0 ; e+j<=n&&e <= num[i]*o[num[i]] ; e+=num[i])
    39             {
    40                 c2[j+e]+=c1[j];
    41             }
    42             for(j = 0 ; j <= n ;j++)
    43             {
    44                 c1[j] = c2[j];
    45                 c2[j] = 0;
    46             }
    47         }
    48         cout<<c1[n]<<endl;
    49     }
    50     return 0;
    51 }
    View Code

    HDU 1521 排列组合  指数型母函数 (见上个)

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define LL long long
    12 #define INF 0xfffffff
    13 const double eps = 1e-8;
    14 const double pi = acos(-1.0);
    15 const double inf = ~0u>>2;
    16 double c1[22],c2[22];
    17 int b[12];
    18 int cn(int x)
    19 {
    20     int i,s=1;
    21     for(i = 1; i <= x ; i++)
    22     s*=i;
    23     return s;
    24 }
    25 int main()
    26 {
    27     int i,j,n,m;
    28     while(cin>>n>>m)
    29     {
    30         memset(c1,0,sizeof(c1));
    31         memset(c2,0,sizeof(c2));
    32         for(i = 1; i <= n; i++)
    33         {
    34             cin>>b[i];
    35         }
    36         for(i = 0 ;i<=b[1] ;i++)
    37         c1[i] = 1.0/cn(i);
    38         for(i = 2; i <= n ;i++)
    39         {
    40             for(j = 0 ;j <= m ;j++)
    41             {
    42                 for(int g = 0 ; g <= b[i] ; g++)
    43                 c2[j+g] += 1.0*c1[j]/cn(g);
    44             }
    45             for(j = 0 ; j <= m ;j++)
    46             {
    47                 c1[j] = c2[j];
    48                 c2[j] = 0;
    49             }
    50         }
    51         printf("%0.lf
    ",c1[m]*cn(m));
    52     }
    53     return 0;
    54 }
    View Code

     hdu 1812 polya 数太大直接用JAVA了 

    旋转 0   n*n

    90    偶数 n*n/4 奇数 (n*n-1)/4

    180  偶数 n*n/2 奇数 (n*n-1)/2 

    270  偶数 n*n/4 奇数 (n*n-1)/4

    对角折  (n*n-n)/2+n 两次 

    中线折 偶数 (n*n)/2  奇数(n*n-n)/2+n 两次

     1 import java.text.*;
     2 import java.io.*;
     3 import java.util.*;
     4 import java.math.*;
     5 import java.applet.*;
     6 public class Main 
     7 {
     8     public static void main(String args[])
     9     {
    10         BigInteger cnt;
    11         Scanner cin = new Scanner(System.in);
    12         int i,j,n,m;
    13         while(cin.hasNextInt())
    14         {
    15             n = cin.nextInt();
    16             m = cin.nextInt();
    17             cnt = BigInteger.valueOf(0);
    18             BigInteger bn = BigInteger.valueOf(m);
    19             cnt = cnt.add(bn.pow(n*n));
    20             if(n%2==0)
    21             {
    22                 cnt = cnt.add(bn.pow(n*n/4).multiply(BigInteger.valueOf(2)));
    23                 cnt = cnt.add(bn.pow(n*n/2));
    24                 cnt = cnt.add(bn.pow((n*n-n)/2+n).multiply(BigInteger.valueOf(2)));
    25                 cnt = cnt.add(bn.pow(n*n/2).multiply(BigInteger.valueOf(2)));
    26             }
    27             else
    28             {
    29                 cnt = cnt.add(bn.pow((n*n-1)/4+1).multiply(BigInteger.valueOf(2)));
    30                 cnt = cnt.add(bn.pow((n*n-1)/2+1));
    31                 cnt = cnt.add(bn.pow((n*n-n)/2+n).multiply(BigInteger.valueOf(4)));
    32             }
    33             System.out.println(cnt.divide(BigInteger.valueOf(8)));
    34         }
    35     }
    36 }
    View Code

     POJ 1286 Necklace of Beads   经典的polay计数 

    其实对于burnside不是特别的理解 只是大体的记得了公式 大体了解 知道哪一类题是用它来解的。 下面可能会把点说成珠子。。。

    文库里讲的都很清楚 可以初步了解下 这个题大体说一下  抛开重复不说 对于每个点可以染k种颜色 那么可以染的可能为n^k 因为旋转或者翻转使得一些可能变成了相同的 这时候就要删除相同的  引入置换的概念 举个例子就是在某种置换下 a->b c->d 也就是说本来该是 4^k  现在对折置换之后 a与b c与d 其实是一样的 那么很明显就变成了2^k。

     这个题 包括两种置换 一是 旋转置换 二是 翻转置换 

    对于旋转: 套定理 k^gcd(i,n) (0<i<=n)

    对于翻转: 因为要对折  就要考虑奇数 和偶数  奇数: 沿穿过每个珠子的线对折 n个置换 ((n-1)/2+1)^k

    偶数 沿穿过珠子的线 n/2个置换 ((n-2)/2+2)^k 不穿过珠子的线 n/2个置换 (n/2)^k

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100000
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 int gcd(int a,int b)
    18 {
    19     return b==0?a:gcd(b,a%b);
    20 }
    21 int main()
    22 {
    23     int i,n;
    24     while(cin>>n)
    25     {
    26         if(n==-1) break;
    27         LL s = 0;
    28         if(n==0)
    29         {
    30             cout<<"0
    ";
    31             continue;
    32         }
    33         for(i = 1 ; i <= n ;i++)
    34         {
    35             s+=(LL)pow(3.0,gcd(i,n));
    36         }
    37         if(n%2==0)
    38         cout<<(s+n/2*(LL)pow(3.0,(n-2)/2+2)+n/2*(LL)pow(3.0,n/2))/2/n<<endl;
    39         else
    40         cout<<(s+n*(LL)pow(3.0,(n-1)/2+1))/2/n<<endl;
    41     }
    42     return 0;
    43 }
    View Code

    POJ 2409 Let it Bead 同上 其实上题的题解该是本题的 上一题的K就是为3

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100000
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 int gcd(int a,int b)
    18 {
    19     return b==0?a:gcd(b,a%b);
    20 }
    21 int main()
    22 {
    23     int i,n,k;
    24     while(cin>>k>>n)
    25     {
    26         if(!n&&!k) break;
    27         if(n==0)
    28         {
    29             cout<<"0
    ";
    30             continue;
    31         }
    32         LL s = 0;
    33         for(i = 1 ; i <= n ;i++)
    34         {
    35             s+=(LL)pow(k*1.0,gcd(i,n));
    36         }
    37         if(n%2==0)
    38         cout<<(s+n/2*(LL)pow(k*1.0,(n-2)/2+2)+n/2*(LL)pow(k*1.0,n/2))/2/n<<endl;
    39         else
    40         cout<<(s+n*(LL)pow(k*1.0,(n-1)/2+1))/2/n<<endl;
    41     }
    42     return 0;
    43 }
    View Code

    POJ 1026 Cipher 这个属于置换群的题 找出循环节 总循环节就等于lcm(x1,x2,x3) 所有的循环节的最小公倍数

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<cmath>
     7 using namespace std;
     8 #define LL long long
     9 LL gcd(LL a,LL b)
    10 {
    11     return b==0?a:gcd(b,a%b);
    12 }
    13 char s[210],ss[210];
    14 int a[210],q[210][210],o[210];
    15 int b[210];
    16 bool vis[210];
    17 int main()
    18 {
    19     int i,j,n,m;
    20     while(cin>>n)
    21     {
    22         if(!n) break;
    23         memset(vis,0,sizeof(vis));
    24         for(i = 1; i <= n ;i++)
    25         scanf("%d",&a[i]);
    26         int kk = 0;
    27         for(i = 1; i <= n; i++)
    28         {
    29             if(!vis[i])
    30             {
    31                 kk++;
    32                 int g = 0;
    33                 q[kk][++g] = i;
    34                 vis[i]=1;
    35                 int x = a[i];
    36                 while(!vis[x])
    37                 {
    38                     vis[x] = 1;
    39                     q[kk][++g] = x;
    40                     x = a[x];
    41                 }
    42                 o[kk] = g;
    43             }
    44         }
    45         LL lcm = 1;
    46         for(i = 1; i <= kk ; i++)
    47         {
    48             lcm = lcm/gcd(lcm,o[i])*o[i];
    49         }
    50         while(scanf("%d%*c",&m)!=EOF)
    51         {
    52             if(!m) break;
    53             gets(s);
    54             int k = strlen(s);
    55             for(i = k ; i < n ;i++)
    56             s[i] = ' ';
    57             s[n] = '';
    58             m = m%lcm;
    59             for(i = 1; i <= kk ;i++)
    60             {
    61                 int ko = m%o[i];
    62                 for(j = 1; j <= o[i] ; j++)
    63                 {
    64                     if(j+ko<=o[i])
    65                     b[q[i][j]] = q[i][j+ko];
    66                     else
    67                     {
    68                         b[q[i][j]] = q[i][j+ko-o[i]];
    69                     }
    70                 }
    71             }
    72             for(i = 0 ;i < n ; i++)
    73             {
    74                 ss[b[i+1]] = s[i];
    75             }
    76             for(i = 1 ;i <= n ;i++)
    77             printf("%c",ss[i]);
    78             puts("");
    79         }
    80         puts("");
    81     }
    82     return 0;
    83 }
    View Code

    POJ 1721 CARDS 这个题说是置换幂的应用  也是先找出循环节 然后减去m次(这里根据长度 变换一下)  就是逆运算 变回去 

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 #define N 1010
    10 int a[N],b[N][N];
    11 int main()
    12 {
    13     int i,j,n,m;
    14     while(scanf("%d%d",&n,&m)!=EOF)
    15     {
    16         for(i = 1; i <= n ;i++)
    17         {
    18             scanf("%d",&a[i]);
    19             b[1][i] = a[i];
    20         }
    21         for(i = 2; ; i++)
    22         {
    23             for(j = 1; j <= n ;j++)
    24             {
    25                 b[i][j] = b[i-1][b[i-1][j]];
    26             }
    27             /*for(j = 1; j <= n ;j++)
    28             cout<<b[i][j]<<" ";
    29             puts("");*/
    30             for(j = 1; j <= n ;j++)
    31             {
    32                 if(b[i][j]!=b[1][j]) break;
    33             }
    34 
    35             if(j==n+1) break;
    36         }
    37         int k = i-1;
    38         m = m%k;
    39         //cout<<m<<endl;
    40         for(i = 1; i <= n; i++)
    41         printf("%d
    ",b[k+1-m][i]);
    42     }
    43     return 0;
    44 }
    View Code

    POJ 3128 Leonardo's Notebook  算是置换开方的应用 有结论是 偶数度的循环节是可以由两个相同偶数度的结合而来 奇数则有奇数而来 具体看一下置换群快速幂运算的研究

    这样就可以在给出的串中找每个循环(也称置换也称轮换)的循环节  看偶数度的是否是成对出现 是 则一定可以有某个置换平方而来 不然则不可以

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100000
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 char s[30],ss[30];
    18 int p[500];
    19 bool vis[500];
    20 int main()
    21 {
    22     int i,j,n;
    23     cin>>n;
    24     while(n--)
    25     {
    26         memset(vis,0,sizeof(vis));
    27         memset(p,0,sizeof(p));
    28         cin>>s;
    29         for(i = 0  ;i < strlen(s) ; i++)
    30         {
    31             if(!vis[i])
    32             {
    33                 vis[i] = 1;
    34                 j = s[i]-'A';
    35                 int o = 1;
    36                 while(!vis[j])
    37                 {
    38                     vis[j] = 1;
    39                     j = s[j]-'A';
    40                     o++;
    41                 }
    42                 p[o]++;
    43             }
    44         }
    45         int ans=0;
    46         for(i = 2; i <= 26 ; i+=2)
    47         if(p[i]%2) break;
    48         if(i<=26) puts("No");
    49         else puts("Yes");
    50     }
    51     return 0;
    52 }
    View Code

    POJ 3590  The shuffle Problem  也是属于置换 不过涉及到最小公倍数最小 即总循环节最小 要把整数拆分为最小公倍数最大 我用dp+置换解的

     先dp出最小公倍数最大的解 然后依次枚举字典序最小 也就是前几块分割长度越小越好 

      1 #include <iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<stdlib.h>
      6 #include<vector>
      7 #include<cmath>
      8 #include<queue>
      9 #include<set>
     10 using namespace std;
     11 #define N 100000
     12 #define LL long long
     13 #define INF 0xfffffff
     14 const double eps = 1e-8;
     15 const double pi = acos(-1.0);
     16 const double inf = ~0u>>2;
     17 int p[110],g,b[110];
     18 LL dp[110][110];
     19 int o[110][110],sum[110];
     20 int w[110],pp[110],q[110];
     21 LL gcd(LL a,LL b)
     22 {
     23     return b==0?a:gcd(b,a%b);
     24 }
     25 void init(int n)
     26 {
     27     int i,j;
     28     sum[0] = 0;
     29     for(i = 1; i <= n ;i++)
     30     {
     31         sum[i] = sum[i-1]+1;
     32         dp[1][i] = sum[i];
     33     }
     34     for(i = 2; i <= n ; i++)
     35         for(j = n; j >= 1 ; j--)
     36         for(g = 1; g < j; g++)
     37         {
     38             LL k = dp[i-1][g]/gcd(dp[i-1][g],sum[j]-sum[g])*(sum[j]-sum[g]);
     39             if(dp[i][j]<=k)
     40             {
     41                 dp[i][j] =k;
     42                 o[i][j] = g;
     43             }
     44         }
     45 }
     46 int main()
     47 {
     48     int i,j,n,t;
     49     cin>>t;
     50     while(t--)
     51     {
     52         cin>>n;
     53         memset(dp,0,sizeof(dp));
     54         init(n);
     55         LL ans = 1;
     56         LL maxz = 0;
     57         int x;
     58         pp[0] = n;
     59         for(i = 1; i <= n  ;i++)
     60         {
     61             if(maxz<=dp[i][n])
     62             {
     63                 x = i;
     64                 maxz = dp[i][n];
     65             }
     66             pp[i] = n;
     67         }
     68         int gg;
     69         for(i = 2; i <= n;i++)
     70         {
     71             if(dp[i][n]==maxz)
     72             {
     73                 int g = 0;
     74                 x = i;
     75                 int y = o[x][n];
     76                 p[++g] = y;x--;
     77                 while(x!=1)
     78                 {
     79                     y = o[x][y];
     80                     p[++g] = y;
     81                     x--;
     82                 }
     83                 int l=0;
     84                 p[g+1] = 0;
     85                 p[0] = n;
     86                 for(j = 1 ; j <=g+1 ; j++)
     87                 {
     88                     q[l++] = p[j-1]-p[j];
     89                 }
     90 
     91                 sort(q,q+l);
     92                 int f = 1;
     93                 for(j = 0 ;j < l ;j++)
     94                 {
     95                     if(q[j]>pp[j]) {
     96                         f = 0;
     97                         break;
     98                     }
     99                     else if(q[j]<pp[j]) break;
    100                 }
    101                 if(f)
    102                 {
    103                     gg = l;
    104                     for(j = 0; j < l ;j++)
    105                         pp[j] = q[j];
    106                 }
    107             }
    108 
    109         }
    110         cout<<maxz<<" ";
    111         int tt=0;
    112         for(i = 0; i < gg  ; i++)
    113         {
    114             for(j = tt+1 ; j <= tt+pp[i]; j++)
    115             {
    116                 if(j+1<=pp[i]+tt)
    117                 b[j] = j+1;
    118                 else
    119                 b[j] = tt+1;
    120             }
    121             tt+=pp[i];
    122         }
    123         if(n==1) b[1] = 1;
    124         for(i = 1; i < n; i++)
    125         cout<<b[i]<<" ";
    126         cout<<b[n]<<endl;
    127     }
    128     return 0;
    129 }
    View Code
  • 相关阅读:
    Fiddler 教程
    Snippet Compiler——代码段编译工具
    HTML5 Audio时代的MIDI音乐文件播放
    sql 数据库 庞大数据量 需要分表
    使用LINQ查询非泛型类型
    找出numpy array数组的最值及其索引
    list的*运算使用过程中遇到的问题
    4.keras实现-->生成式深度学习之用GAN生成图像
    np.repeat 与 np.tile
    pandas中的axis=0,axis=1,傻傻分不清楚
  • 原文地址:https://www.cnblogs.com/shangyu/p/3577427.html
Copyright © 2011-2022 走看看