Comet OJ - Contest #7 解题报告

传送门:https://www.cometoj.com/contest/52


A:签到题

题意:多次询问,每次询问给出一个值域区间[l,r],从这区间范围中选出两个整数(可重复),依次求出这俩数的“最大的最小公倍数”、“最小的最小公倍数”、“最大的最大公约数”、最小的最大公约数。

分析:(1)显然,当区间长度为1时,该问题的答案只能是区间中仅有的那个数。

   (2)当区间的长度大于1时,最大的最小公倍数,lcmmax =lcm(ar,ar-1) = ar * ar-1;

                最小的最小公倍数,lcmmin = lcm(al,al) = al;

                最大的最大公约数,gcdmax = gcd(ar,ar) = ar;

                最小的最大公约数,gcdmin = gcd(ar,ar-1) = 1;

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() {
 6     int t;
 7     scanf("%d",&t);
 8     while (t--) {
 9         int l,r;
10         scanf("%d%d",&l,&r);
11 
12         if (l == r) {
13             printf("%d %d %d %d\n",l,l,l,l);
14         } else {
15             printf("%lld %d %d %d\n",(long long)r*(r-1),l,r,1);
16         }
17     }
18 
19     return 0;
20 }
View Code

B:麻将题

题意:4个人(编号为1~4)围成一个环,相邻两人可以交换位置。现按逆时针顺序给出环上的编号,代表4人在桌上的位置关系。求最少需要交换多少次位置才能满足1的下一个元素是2,2的下一个元素是3,3的下一个元素是4,4的下一个元素是1。

分析:由于环上只有4个元素,交换次数最多不会超过2次,因此我们可以考虑直接枚举情况。

   (1)假如这个序列一开始就满足条件,最少交换次数为 0。

   (2)假如这个序列的位置关系为(1,4,3,2),最少交换次数为 2。

   (3)其余情况最少交换次数均为 1。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() {
 6     int num[4],pos = 0;
 7     for (int i=0;i<4;i++) {
 8         scanf("%d",&num[i]);
 9         if (num[i] == 1)
10             pos = i;
11     }
12 
13     int arr[4];
14     int pick[4] = {1,4,3,2};
15     bool two = true;
16     for (int i = 0;i<4;i++) {
17         arr[i] = num[pos];
18         pos = (pos + 1)%4;
19         if (arr[i] != pick[i]) {
20             two = false;
21         }
22     }
23 
24     if (two) {
25         puts("2");
26     } else {
27         int i = 1;
28         for (;i<4;i++) {
29             if (arr[i] != arr[i-1] + 1) {
30                 break;
31             }
32         }
33         if (i == 4) {
34             puts("0");
35         } else {
36             puts("1");
37         }
38     }
39 
40     return 0;
41 }
View Code

 C:临时翻出来的题

题意:n张牌,每张牌有一个编号,一个合法的排列规定编号为i的牌不能放在pi上。记编号为i的牌的位置为posi,对于所有两张牌的组合(设这两张牌的编号为i和j),若满足j > i且posj < posi,那么产生的贡献为|j - i| * |posi - posj|,否则贡献值为0。求所有合法的排列的贡献值之和。

分析:(1)状态的设置:S表示状态

               f[S] 表示状态S的贡献

             t[S] 表示状态S的种类数

             g[S][x] 表示位置x上的牌在每种方案中的编号之和

   (2)枚举每一个状态S,对于每一个状态,枚举该状态下有牌的位置pos,表示上个状态在pos的位置插了新牌后,由此我们可以推回上个状态,通过上个状态的信息,我们可以更新(1)的信息。最后f[(1<<n)-1]的值即为我们要求的答案。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int p[17];
 6 long long f[1<<16],t[1<<16],g[1<<16][17];
 7 /*
 8 S表示状态
 9 f[S] 表示状态S的贡献
10 t[S] 表示状态S的种类数
11 g[S][x] 表示位置x上的牌在每种方案中的编号之和
12 */
13 int bitcount(int x) {
14     return x?bitcount(x>>1) + (x&1):0;
15 }
16 
17 int main() {
18     int T;
19     scanf("%d",&T);
20 
21     while (T--) {
22         int n;
23         scanf("%d",&n);
24 
25         for (int i=1;i<=n;i++) {
26             scanf("%d",&p[i]);
27         }
28 
29         memset(f,0,sizeof(f));
30         memset(t,0,sizeof(t));
31         memset(g,0,sizeof(g));
32 
33         t[0] = 1;
34         for (int s=1;s<(1<<n);s++) {
35             int y = bitcount(s);
36             for (int x=1;x<=n;x++) {
37                 if (x != p[y] && (s&1<<(x-1))) {
38                     int las = s ^ 1 << (x-1);
39                     f[s] += f[las];
40                     t[s] += t[las];
41                     g[s][x] += t[las]*y;
42                     for (int z=x+1;z<=n;z++) {
43                         if (las & 1<<(z-1)) {
44                             f[s] += (z-x)*(t[las]*y - g[las][z]);
45                         }
46                     }
47                     for (int i=1;i<=n;i++) {
48                         g[s][i] += g[las][i];
49                     }
50                 }
51             }
52         }
53 
54         printf("%lld\n",f[(1<<n)-1]);
55     }
56 
57     return 0;
58 }
View Code
posted @ 2019-08-13 19:40  DoubleBit  阅读(228)  评论(0)    收藏  举报