组合基础小记

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

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

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\n",(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\n";
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\n",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\n";
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\n";
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] = '\0';
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\n",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

 

 

 

 

posted @ 2014-03-02 22:27  _雨  阅读(227)  评论(0编辑  收藏  举报