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 }
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 }
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 }


浙公网安备 33010602011771号