数论一

1、UVa 10916  Factstone Benchmark(对数函数的利用--乘化加)

  题意:给出年份,每个10年对应一个当前计算机可支持的字节位数,计算n! < max(max 为当前计算机能表示的最大整数),求最大n.

  思路:字节数k = (year - 1940) / 10,  问题就转化成 n ! < 2 ^ k < (n + 1) !, 对两边同取对数,因为log(a*b) = log(a) + log(b);所以log(n!) = sum(log(i)), ( 1<= i <= n), 只要找到最小的sum(log(i)) > k * log(2) ,答案就是i- 1.

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 int main()
 5 {
 6     int y;
 7     while (~scanf("%d", &y)&&y)
 8     {
 9         int n = (y - 1940) / 10;
10         double re = pow(2.0,1.0*n)*log(2.0);
11         double sum = 0;
12         for(int i=1;;i++)
13         {
14             sum += log(1.0*i);
15             if (sum > re)
16             {
17                 printf("%d\n", i - 1);
18                 break;
19             }
20         }
21     }
22     return 0;
23 }

2、zoj 1239 Hanoi Tower Troubles Again!

  题意:给出n个柱子,从第一个柱子开始放珠子,珠子编号从1开始,要求每个柱子上相邻两个珠子的和是平方数。

  思路:

h(1) = 1:1个柱子时,放上1之后,2就放不上去了,不满足柱子上相邻的球之和为平方数(1 + 2 = 3,不是平方数);
h(2) = 3:2个柱子时,1和2各放在1个柱子上,3可以放在1上面(1 + 3 = 4 = 2 ^ 2);
h(i) = h(i - 1) + i + 1:i为奇数时,在i - 1柱子的基础上增加了一个柱子,这时候可以再放i + 1个球;
h(i) = h(i - 1) + i:i为偶数时,在i - 1柱子的基础上增加了一个柱子,这时候可以再放i个球。
f(n) = f(n - 1) + (n + 1) / 2 + (n + 1) / 2 (n > 2)

 1 //h(1) = 1:1个柱子时,放上1之后,2就放不上去了,不满足柱子上相邻的球之和为平方数(1 + 2 = 3,不是平方数);
 2 //h(2) = 3:2个柱子时,1和2各放在1个柱子上,3可以放在1上面(1 + 3 = 4 = 2 ^ 2);
 3 //h(i) = h(i - 1) + i + 1:i为奇数时,在i - 1柱子的基础上增加了一个柱子,这时候可以再放i + 1个球;
 4 //h(i) = h(i - 1) + i:i为偶数时,在i - 1柱子的基础上增加了一个柱子,这时候可以再放i个球。
 5 // f(n) = f(n - 1) + (n + 1) / 2 + (n + 1) / 2    (n > 2)
 6 #include<iostream>
 7 using namespace std;
 8 int re[55];
 9 void Init()
10 {
11     re[1] = 1, re[2] = 3;
12     for (int i = 3; i <= 50; i++) re[i] = re[i - 1] + (i + 1) / 2 + (i + 1) / 2;
13 }
14 int main()
15 {
16     Init();
17     int t;
18     scanf("%d", &t);
19     while (t--)
20     {
21         int n;
22         scanf("%d", &n);
23         printf("%d\n", re[n]);
24     }
25     return 0;
26 }

3、hdu1465 不容易系列之一(错排)

  题意:求所有错排的错排方案数。

  思路:

错排数公式:f[n] = (n - 1) * (f[n - 1] + f[n - 2]);
也可以这么想;
(1).f[1] = 0; f[2] = 1;
(2).如果确定f[n - 1] 和 f[n - 2] 的话。
f[n] 中必然包含 f[n - 1] * (n - 1)种情况。 即把新加入的一封和之前的任一一封交换,所得到的必然是错排。

 1 //错排数公式:f[n] = (n - 1) * (f[n - 1] + f[n - 2]);
 2 //也可以这么想;
 3 //(1).f[1] = 0; f[2] = 1;
 4 //(2).如果确定f[n - 1] 和 f[n - 2] 的话。
 5 //f[n] 中必然包含 f[n - 1] * (n - 1)种情况。 即把新加入的一封和之前的任一一封交换,所得到的必然是错排。
 6 //f[n] 中另一部分就是f[n - 2] * (n - 1) 即之前的 n - 1 封中有一封没有错排,把这封与新加入的一封交换进行错排。
 7 #include<iostream>
 8 using namespace std;
 9 long long re[25];
10 void Init()
11 {
12     re[1] = 0, re[2] = 1;
13     for (int i = 3; i <= 20; i++) re[i] = (re[i - 1] + re[i - 2])*(i - 1);
14 }
15 int main()
16 {
17     Init();
18     int n;
19     while (~scanf("%d", &n))
20     {
21         printf("%lld\n",re[n]);
22     }
23     return 0;
24 }

4、HDU 3625 Examining the Rooms(第一类斯特林数)

  题意:有n个房间,n!个钥匙,在房间中,最多可以破k扇门,然后得到其中的钥匙,去开其它的门,但是第一扇门不可以破开,求可以打开所有门的概率。

  思路:

求N个房间形成1~K个环有多少种可能,然后除以总的分配方案数即为题目要我们求的概率。

第一类斯特林数S(N, K) = S(N - 1, K - 1) + (N - 1)*S(N - 1, k)恰恰就是求N个元素形成K个非空循环排列的方法数。

S(N,M)-S(N-1,M-1),表示N个元素形成M个环,减去1独自成环,即剩下的N-1个元素形成M-1个环,算得的结果便是所求值。

 1 //求N个房间形成1~K个环有多少种可能,然后除以总的分配方案数即为题目要我们求的概率
 2 //第一类斯特林数S(N, K) = S(N - 1, K - 1) + (N - 1)*S(N - 1, k)恰恰就是求N个元素形成K个非空循环排列的方法数
 3 //S(N,M)-S(N-1,M-1),表示N个元素形成M个环,减去1独自成环,即剩下的N-1个元素形成M-1个环,算得的结果便是所求值
 4 #include<iostream>
 5 using namespace std;
 6 long long stl[25][25], cal[25];
 7 void Init()
 8 {
 9     cal[0] = cal[1] = 1;
10     for (int i = 2; i <= 20; i++) cal[i] = cal[i - 1] * i;
11     for (int i = 1; i <= 20; i++)
12     {
13         stl[i][i] = 1;
14         for (int j = 1; j < i; j++)
15         {
16             stl[i][j] = stl[i - 1][j - 1] + (i - 1)*stl[i - 1][j];
17         }
18     }
19 }
20 int main()
21 {
22     int t;
23     scanf("%d", &t);
24     Init();
25     while (t--)
26     {
27         int n, k;
28         scanf("%d%d", &n, &k);
29         long long ans = 0;
30         for (int i = 1; i <= k; i++)
31         {
32             ans += stl[n][i] - stl[n - 1][i - 1];
33         }
34         printf("%.4lf\n", 1.0*ans / cal[n]);
35     }
36     return 0;
37 }

5、hdu 4045 Machine scheduling(组合+第二类斯特林数)

  题意:有N个机器,每天选出R个机器,而且每两个机器的编号差要大于等于K,而且每天将R个机器最多分为M组工作,问最多有多少种方案 。

  思路:

首先是从N个机器中选出R个满足条件的机器有多少种。然后将R个机器最多分为M组有多少种,答案为二者的乘积。

对于后者:

为第二类Strling数的和 : S[n][1] + S[n][2] + ... + S[n][m]。

S(p,k)的递推公式是:S(p,k)=k*S(p-1,k)+S(p-1,k-1) ,1<= k<=p-1
边界条件:S(p,p)=1 ,p>=0 ;S(p,0)=0 ,p>=1。

对于前者:

1:如果是把n个求放入k个盒子中(每个盒子必须要有球),那么由插板法得 方案数为 C(n-1,k-1);
2:如果是把n个求放入k个盒子中(盒子可以为空),那么由插板法得 方案数为 C(n + k - 1, k - 1);
要从n个元素编号1~n中选出r个元素来,使得任意两个元素编号相差>=k
解法:先按照 1 k + 1 2 * k + 1 .... (r - 1)*k + 1 也就是刚好 间隔 k个排列下来
那么 总共n个元素,剩余 n - (r - 1)*k - 1个元素可以看成空格,极为space, 将它们插入这r个元素的r + 1个空档中,
这样就能保证枚举了素有的方法数,切满足任意两个元素编号相差 >= k的要求
所以这个问题简化为:将space个元素分配到r + 1个区域中,可以为空(每两个机器之前至少有K个间隔,那么如果还剩余一些位置,则把这些多余的插入到R个机器中。那么剩余位置便是N - ((R - 1)*K + 1), 对于R个机器,R + 1个位置,接下来便是把N - ((R - 1)*K + 1)分为R + 1个集合,而且可以为空。做法是添加R + 1个物品,然后用插板法,这样保证 每一个集合都至少有一个,然后再把每一个集合都减掉一个便是结果,最终结果便是C[N - ((R - 1)*K + 1) + R + 1 - 1][R]。)

 1 //有N个机器,每天选出R个机器,而且每两个机器的编号差要大于等于K,而且每天将R个机器最多分为M组工作,问最多有多少种方案
 2 //1:如果是把n个求放入k个盒子中(每个盒子必须要有球),那么由插板法得 方案数为 C(n-1,k-1);
 3 //2:如果是把n个求放入k个盒子中(盒子可以为空),那么由插板法得 方案数为 C(n + k - 1, k - 1);
 4 //要从n个元素编号1~n中选出r个元素来,使得任意两个元素编号相差>=k
 5 //解法:先按照 1 k + 1 2 * k + 1 .... (r - 1)*k + 1 也就是刚好 间隔 k个排列下来
 6 //那么 总共n个元素,剩余 n - (r - 1)*k - 1个元素可以看成空格,极为space, 将它们插入这r个元素的r + 1个空档中,
 7 //这样就能保证枚举了素有的方法数,切满足任意两个元素编号相差 >= k的要求
 8 //所以这个问题简化为:将space个元素分配到r + 1个区域中,可以为空(每两个机器之前至少有K个间隔,那么如果还剩余一些位置,则把这些多余的插入到R个机器中。那么剩余位置便是N - ((R - 1)*K + 1), 对于R个机器,R + 1个位置,接下来便是把N - ((R - 1)*K + 1)分为R + 1个集合,而且可以为空。做法是添加R + 1个物品,然后用插板法,这样保证 每一个集合都至少有一个,然后再把每一个集合都减掉一个便是结果,最终结果便是C[N - ((R - 1)*K + 1) + R + 1 - 1][R]。)
 9 #include<iostream>
10 using namespace std;
11 const int maxn = 1010;
12 const int MOD = 1e9 + 7;
13 long long C[maxn][maxn];
14 long long stri2[maxn][maxn];//第二类斯特林数
15 void Init()
16 {
17     memset(C, 0, sizeof(C));
18     for (int i = 0; i < maxn; i++)
19     {
20         C[i][0] = 1;
21         for (int j = 1; j <= i; j++)
22         {
23             C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
24         }
25     }
26     for (int i = 1; i < maxn; i++)
27     {
28         stri2[i][0] = 0;
29         stri2[i][i]=stri2[i][1] = 1;
30         for (int j = 1; j < i; j++)
31         {
32             stri2[i][j] = (stri2[i - 1][j] * j + stri2[i - 1][j - 1]) % MOD;
33         }
34     }
35 }
36 int main()
37 {
38     Init();
39     int n, r, k, m;
40     while (~scanf("%d%d%d%d", &n, &r, &k, &m))
41     {
42         int res = n - (r - 1)*k - 1;
43         if (res < 0)
44         {
45             printf("0\n");
46             continue;
47         }
48         long long ans = 0;
49         for (int i = 0; i <= m; i++) ans = (ans + stri2[r][i]) % MOD;
50         ans = (ans*C[res + r][r]) % MOD;
51         printf("%lld\n", ans);
52     }
53     return 0;
54 }

6、HDU 1023 Train Problem II(卡特兰数+模拟大数乘除<高精度递推>)

  题意:给你一个数n,表示有n辆火车,编号从1到n,从远方驶过来,问你有多少种出站的可能。

  思路:

1.Catalan数的组合公式为 Cn=C(2n,n) / (n+1);
2.此数的递归公式为 h(n ) = h(n-1)*(4*n-2) / (n+1)。

http://blog.163.com/lz_666888/blog/static/1147857262009914112922803/

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int cat[110][110];//每一位存放大数的4位
 6 //Catalan数的组合公式为 Cn=C(2n,n) / (n+1);
 7 //递推公式为 h(n) = h(n - 1)*(4 * n - 2) / (n + 1);
 8 int length[110];//记录每一位卡特兰数的位数
 9 const int MOD = 10000;
10 void Init()
11 {//求出1~100位卡特兰数
12     memset(cat, 0, sizeof(cat));
13     cat[1][0] = 1;
14     int len = 1;
15     length[1] = 1;
16     for (int i = 2; i <= 100; i++)
17     {
18         //乘法
19         int r = 0;
20         for (int j = 0; j < len; j++)
21         {
22             int temp = cat[i - 1][j] * (4 * i - 2);
23             cat[i][j] = (temp+r)%MOD;
24             r = (temp + r) / MOD;
25         }
26         //进位
27         while (r)
28         {
29             cat[i][len++] = r %MOD;
30             r /= MOD;
31         }
32         //除法
33         r = 0;
34         for (int j = len - 1; j >= 0; --j)
35         {
36             int temp = r * MOD + cat[i][j];
37             cat[i][j] = temp / (i + 1);
38             r = temp % (i + 1);
39         }
40         //除法结束后高位0处理
41         while (cat[i][len - 1] == 0)
42         {
43             len--;
44         }
45         length[i] = len;
46     }
47 }
48 int main()
49 {
50     Init();
51     int n;
52     while (~scanf("%d", &n))
53     {
54         int len = length[n];
55         printf("%d", cat[n][len - 1]);
56         for (int j = len - 2; j >= 0; j--) printf("%.4d", cat[n][j]);
57         printf("\n");
58     }
59     return 0;
60 }

7、HDU 1297 Children’s Queue(模拟大数加法<高精度递推>)

  题意:F代表女孩,M代表男孩,女孩不能单独出现但是可以不出现,即不能出现MFM这种情况,给定一个数n,问有多少种站队方式。

  思路:

一个长度n的队列可以看成一个n - 1的队列再追加的1个小孩,这个小孩只可能是:
a.男孩,任何n - 1的合法队列追加1个男孩必然是合法的,情况数为f[n - 1];
b.女孩,在前n - 1的以女孩为末尾的队列后追加1位女孩也是合法的,我们可以转化为n - 2的队列中追加2位女孩;
一种情况是在n - 2的合法队列中追加2位女孩,情况数为f[n - 2];
但我们注意到本题的难点,可能前n - 2位以女孩为末尾的不合法队列(即单纯以1位女孩结尾),也可以追加2位女孩成为合法队列,而这种n - 2不合法队列必然是由n - 4合法队列 + 1男孩 + 1女孩的结构,即情况数为f[n - 4]。
f[n] = f[n - 1] + f[n - 2] + f[n - 4]。

 1 //一个长度n的队列可以看成一个n - 1的队列再追加的1个小孩,这个小孩只可能是:
 2 //a.男孩,任何n - 1的合法队列追加1个男孩必然是合法的,情况数为f[n - 1];
 3 //b.女孩,在前n - 1的以女孩为末尾的队列后追加1位女孩也是合法的,我们可以转化为n - 2的队列中追加2位女孩;
 4 //一种情况是在n - 2的合法队列中追加2位女孩,情况数为f[n - 2];
 5 //但我们注意到本题的难点,可能前n - 2位以女孩为末尾的不合法队列(即单纯以1位女孩结尾),也可以追加2位女孩成为合法队列,而这种n - 2不合法队列必然是由n - 4合法队列 + 1男孩 + 1女孩的结构,即情况数为f[n - 4]。
 6 //f[n] = f[n - 1] + f[n - 2] + f[n - 4]
 7 #include<iostream>
 8 #include<cstring>
 9 using namespace std;
10 int f[1010][1010];
11 int length[1010];
12 void Init()
13 {
14     memset(f, 0, sizeof(f));
15     f[1][0] = 1;
16     f[2][0] = 2;
17     f[3][0] = 4;
18     f[4][0] = 7;
19     int len = 1;
20     length[1] = length[2] = length[3] = length[4] = 1;
21     for (int i = 5; i <= 1000; i++)
22     {
23         for (int j = 0; j < len; j++)
24         {
25             f[i][j] += f[i - 1][j] + f[i - 2][j] + f[i - 4][j];
26             f[i][j + 1] += f[i][j] / 10000;
27             f[i][j] %= 10000;
28         }
29         while (f[i][len]) len++;
30         length[i] = len;
31     }
32 }
33 int main()
34 {
35     Init();
36     int n;
37     while (~scanf("%d", &n))
38     {
39         int len = length[n];
40         printf("%d", f[n][len - 1]);
41         for (int i = len - 2; i >= 0; i--) printf("%04d", f[n][i]);
42         printf("\n");
43     }
44     return 0;
45 }

8、hdu 1466 计算直线交点数

  题意:平面上有n条直线,且无三线共点,问这些直线能有多少种不同交点数。比如,如果n=2,则可能的交点数量为0(平行)或者1(不平行)。

  思路:

分析加入第N条直线的情况(这里以N=4为例): 
(分类方法:和第N条直线平行的在a组,其余在b组) 
1、 第四条与其余直线全部平行 :

0+4*0+0=0;

2、 第四条与其中两条平行:

交点数为0+(n-1)*1+0=3;

3、 第四条与其中一条平行:

这两条平行直线和另外两点直线的交点数为(n-2)*2=4,

而另外两条直线既可能平行也可能相交,

因此可能交点数为: 0+(n-2)* 2+0=4    或者  0+(n-2)*2+1=5

4、 第四条直线不与任何一条直线平行,交点数为:0+(n-3)*3+0=3  或0+ (n-3)*3+2=5  或0+ (n-3)*3+3=6

即n=4时,有0个,3个,4个,5个,6个不同交点数。

所以从上述n=4的分析过程中,我们发现:

m条直线的交点方案数 =(m - r)条平行线与r条直线交叉的交点数 + r条直线本身的交点方案 = (m - r )* r + r 条之间本身的交点方案数(0 < = r < m )

将 n 条直线排成一个序列,直线 2 和直线 1 最多只有一个交点,直线 3 和直线 1 和直线 2 最多有两个交点......直线n和其他 n - 1 条直线最多有 n - 1 个交点,由此得出 n 条直线互不平行且无三线共点的最多交点数:max = 1 + 2 + . . . + (n - 1) = n * (n - 1) / 2。

其中每个自由直线与每个平行直线都有一个交点,j自由直线与i平行直线的交点数为 j * i,所以n条直线的交点数等于自由直线与平行直线的交点加上自由直线内部形成的交点。

————————以上摘自:http://blog.csdn.net/wang907553141/article/details/52165629

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn = 210;
 4 bool dp[25][maxn];//dp[i][j]表示i条直线相交时是否有j个交点
 5 void Init()
 6 {
 7     for (int i = 0; i <= 20; i++) dp[i][0] = true;//所有的直线都平行
 8     for (int i = 2; i <= 20; i++)
 9     {//i条直线
10         for (int j = 1; j < i; j++)
11         {//枚举和第i条边相交的边的数目
12             for (int k = 0; k < maxn; k++)
13             {//枚举j条边的交点情况
14                 if (dp[j][k]) dp[i][(i - j)*j + k] = true;
15             }
16
17         }
18     }
19 }
20
21 int main()
22 {
23     Init();
24     int n;
25     while (~scanf("%d", &n))
26     {
27         for (int i = 0; i < maxn; i++)
28         {
29             if (dp[n][i])
30             {
31                 if (i > 0) printf(" ");
32                 printf("%d", i);
33             }
34         }
35         printf("\n");
36     }
37     return 0;
38 }

时间: 2024-10-06 19:17:25

数论一的相关文章

NKOJ1236 a^b (数论定理的应用)

          a^b 对于任意两个正整数a,b(0<=a,b<10000)计算a b各位数字的和的各位数字的和的各位数字的和的各位数字的和. Input 输入有多组数据,每组只有一行,包含两个正整数a,b.最后一组a=0,b=0表示输入结束,不需要处理. Output 对于每组输入数据,输出ab各位数字的和的各位数字的和的各位数字的和的各位数字的和. Sample Input 2 3 5 7 0 0 Sample Output 8 5 思路: 数论定理:任何数除以9的余数等于各位数的和除

CodeForces 396A 数论 组合数学

题目:http://codeforces.com/contest/396/problem/A 好久没做数论的东西了,一个获取素数的预处理跟素因子分解写错了,哭瞎了,呵呵, 首先ai最大值为10^9,n为500,最坏的情况 m最大值为500个10^9相乘,肯定不能获取m了,首选每一个ai肯定是m的一个因子,然后能分解就把ai给分解素因子,这样全部的ai都分解了  就能得到m的 所有素因子 以及 所有素因子的个数,题目求的 是n个因子的 不同序列的个数,所以每次 只能选出n个因子,这n个因子由素因子

HDU 4861 Couple doubi(数论)

HDU 4861 Couple doubi 题目链接 题意:给定k,p,有k个球,每个球的值为1^i+2^i+...+(p-1)^i (mod p) (1 <= i <= k),现在两人轮流取球,最后球的值总和大的人赢,问先手是否能赢 思路:先手不可能输,非赢即平,那么只要考虑每种球的值, 利用费马小定理或欧拉定理,很容易得到该函数的循环节为p - 1, 那么i如果为p - 1的倍数,即为循环节的位置,那么每个值都为1,总和为p - 1 如果i不在循环节的位置,任取一个原根g,根据原根的性质,

UVA 10548 - Find the Right Changes(数论)

UVA 10548 - Find the Right Changes 题目链接 题意:给定a,b,c,表示货物的价值,求由A货物和B货物组成C货物有几种方法,判断有无解和是否有无限多种 思路:扩展欧几里得求通解,去计算上限和下限就能判断 代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const long l

hdu 4542 数论 + 约数个数相关 腾讯编程马拉松复赛

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4542 小明系列故事--未知剩余系 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 889    Accepted Submission(s): 207 Problem Description "今有物不知其数,三三数之有二,五五数之有三,七七数之有

[施工中]良心数论.

/* Copyright: xjjppm Author: xjjppm Date: 08-08-17 11:36 Description: Number Theory */ #include <map> #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> inline int input() { char c=getchar();int x=0,a=

信息学中的数论(一)

做oi题目的时候,遇到数论题会令我兴奋不已. 这一篇让我来聊一聊我学过的gcd,lcm,扩展欧几里得算法,逆元,组合数等. 这篇贴的代码都是未经过编译运行的,所以如果有错或有疑问请评论. 恩 那么什么是数论 和数学有关的非几何都是数论? 嘛,我也不知道定义,那么就草率地认为所有和数学有关的非计算几何知识都是数论吧. 我们先来聊一聊gcd. 这个东西,非常的有用. 它的名字叫最大公约数. 正常人都知道,有一个方法叫辗转相除法(证明略): int gcd(int a,int b) { if(!b)r

【数论Day3】进制问题 题解

数论进入第三天,进制问题是常用提醒,是数论的一个重要知识点,常考! 题面:http://www.cnblogs.com/ljc20020730/p/6935255.html 1.K进制数(Kbased.pas/c/cpp) 首先明确数据范围: [数据规模和约定] 对于40%的数据,a的长度不超过5. 对于100%的数据,a的长度不超过100000. 对于40%暴力枚举不多说,上代码: var t,i,k,tt:longint; a:qword; s:string; function pow(x,

Bzoj2219 数论之神

Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 954  Solved: 268 Description 在ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀!一天他在群里面问了一个神题: 对于给定的3个非负整数 A,B,K 求出满足 (1) X^A = B(mod 2*K + 1) (2) X 在范围[0, 2K] 内的X的个数!自然数论之神是可以瞬间秒杀此题的,那么你呢? Inpu

【bzoj4872】[Shoi2017]分手是祝愿 数论+期望dp

题目描述 Zeit und Raum trennen dich und mich. 时空将你我分开. B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态,下标为从 1 到 n 的正整数.每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,游戏的目标是使所有灯都灭掉.但是当操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被改变,即从亮变成灭,或者是从灭变成亮.B 君发现这个游戏很难,于是想到了这样的一个