A:
题意:
有三个项目和n个学生,每个学生都擅长其中一个项目,现在要组成三个人的队伍,其中每个人恰好擅长其中一门,问能组成多少支队伍。
分析:
最多能组成的队伍的个数就是擅长项目里的最少学生。
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 5 using namespace std; 6 7 int main(void) 8 { 9 int n, x; 10 vector<int> a[4]; 11 scanf("%d", &n); 12 for(int i = 1; i <= n; ++i) 13 { 14 scanf("%d", &x); 15 a[x].push_back(i); 16 } 17 int aa = a[1].size(), bb = a[2].size(), cc = a[3].size(); 18 int ans = min(aa, bb); 19 ans = min(ans, cc); 20 printf("%d ", ans); 21 for(int i = 0; i < ans; ++i) 22 printf("%d %d %d ", a[1][i], a[2][i], a[3][i]); 23 24 return 0; 25 }
B:
题意:
有n个学生排成一队,他们有各自的学号(学号互不相同),现在知道每名学生前面那个人的学号ai和后面同学的学号bi,没有前驱或后继的补0,给出的顺序是任意的。要求顺序输出这些学号。
分析:
显然0是我们的突破点。如果n是偶数,从a中的那个0开始往后面推我们能得到排在偶数为的学号,从b中的0往前推,能得到奇数位置的学号。
n为奇数就略为棘手,不管从哪个0开始推,都只能得到偶数位置的学号。所以我们要另外分析奇数位置,发现:第一个学号是a、b中只出现一次且在a中的学号,找到这个头我们就可以往后面推了,当然如果找到的是b中只出现一次的那个尾也可以往前推。
代码比较挫,还是贴上来吧,毕竟是自己的孩子啊。
1 #include <cstdio> 2 3 const int maxn = 1000000 + 10; 4 int left[maxn], right[maxn], cnt[maxn], vis[maxn]; 5 int ans[maxn]; 6 7 int main(void) 8 { 9 //freopen("Bin.txt", "r", stdin); 10 int n, a, b; 11 scanf("%d", &n); 12 for(int i = 0; i < n; ++i) 13 { 14 scanf("%d%d", &a, &b); 15 right[a] = b; 16 left[b] = a; 17 cnt[a]++; 18 cnt[b]++; 19 } 20 if(n % 2 == 0) 21 { 22 int t = 0; 23 for(int i = 2; i <= n; i += 2) 24 { 25 ans[i] = right[t]; 26 t = right[t]; 27 } 28 t = 0; 29 for(int i = n-1; i >= 1; i -= 2) 30 { 31 ans[i] = left[t]; 32 t = left[t]; 33 } 34 } 35 else 36 { 37 int i, t = 0; 38 for(i = 2; i <= n; i += 2) 39 { 40 ans[i] = right[t]; 41 vis[t] = 1; 42 t = right[t]; 43 } 44 for(i = 1; i <= maxn; ++i) 45 if(cnt[i] == 1) break; 46 t = i; 47 if(left[t] == 0) 48 { 49 for(int i = 1; i <= n; i += 2) 50 { 51 ans[i] = t; 52 t = right[t]; 53 } 54 } 55 else 56 { 57 for(int i = n; i >= 1; i -= 2) 58 { 59 ans[i] = t; 60 t = left[t]; 61 } 62 } 63 } 64 for(int i = 1; i < n; ++i) printf("%d ", ans[i]); 65 printf("%d ", ans[n]); 66 67 return 0; 68 }
又去翻了翻牛牛们的代码,发现他没有分奇偶,直接输出的,只弄明白大意。
1 #include <iostream> 2 3 using namespace std; 4 5 const int MAXN = 200010; 6 const int MAXA = 1000010; 7 8 int nex[MAXN]; 9 int rb[MAXA], ra[MAXA]; 10 int a[MAXN], b[MAXN]; 11 12 int main() 13 { 14 //freopen("Bin.txt", "r", stdin); 15 ios_base::sync_with_stdio(false); 16 int n; 17 cin >> n; 18 int st = -1, stid = -1; 19 for (int i = 1; i <= n; i++) 20 { 21 cin >> a[i] >> b[i]; 22 ra[a[i]] = i; 23 rb[b[i]] = i; 24 if (a[i] == 0) 25 st = i; 26 } 27 for (int i = 1; i <= n; i++) 28 if (rb[a[i]] == 0) 29 stid = a[i]; 30 while (st != 0) 31 { 32 cout << stid << " "; 33 int nid = b[st]; 34 st = ra[stid]; 35 stid = nid; 36 } 37 cout << endl; 38 }
C: (高精度取模)
题意:
有一个大数s和两个int a、b,问是否能够将这个大数从中间分隔开,使得前面的数被a整除,后面的数被b整除,且不能有前导0。
分析:
从低位到高位计算低i位数模b的余数,然后从高位到低位计算高i位数模a的余数,如果有一个i的值满足前i位数被a整除后面的数被b整除且b不含前导0,这找到符合要求的分割,输出即可。
s.substr(pos, len)是求s的从pos开始,长度为len的子串。
1 #include <cstdio> 2 #include <string> 3 #include <iostream> 4 using namespace std; 5 6 const int maxn = 1000000 + 10; 7 int mas[maxn]; 8 9 int main() 10 { 11 //freopen("Cin.txt", "r", stdin); 12 ios::sync_with_stdio(false); 13 string s; 14 int a, b; 15 cin >> s >> a >> b; 16 int tmp = 1; 17 mas[s.size()] = 0; 18 for(int i = (int)s.size()-1; i >= 0; --i) 19 { 20 mas[i] = mas[i+1] + tmp * (s[i] - '0'); 21 mas[i] = mas[i] % b; 22 tmp *= 10; 23 tmp = tmp % b; 24 } 25 26 tmp = 0; 27 for(int i = 0; i < (int)s.size()-1; ++i) 28 { 29 tmp = tmp * 10 + (s[i] - '0'); 30 tmp %= a; 31 if(tmp == 0 && s[i+1] != '0') //²»ÄÜÓÐÇ°µ¼0 32 { 33 if(mas[i+1] == 0) 34 { 35 cout << "YES "; 36 cout << s.substr(0, i+1) << " "; 37 cout << s.substr(i+1, s.size()-i-1) << " "; 38 return 0; 39 } 40 } 41 } 42 cout << "NO "; 43 44 return 0; 45 }