组合基础小记

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

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

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

 

 

 

 

你可能感兴趣的:(基础)