CDUT2020寒假训练第一场 题解
好久没有更博客了
前两天跑去打美赛,第一次参加数学建模,选了E题,没想到一直理解不了第一个问题的意思,找了快两天数据……想着用多元非线性回归,结果数据是线性的,线性回归r值为1……
心态不太好于是放弃二月份准备三月份的了orz
我讨厌塑料垃圾
以下正文
A
CF 1030C
链接:http://codeforces.com/problemset/problem/1030/C
题意:给100个以内的数字,求是否能把这些数字划分成两个或以上和相等的部分,不能改变数字顺序
思路:因为最多只有100个数,可以直接暴力求解,2个思路,一个是求和之后直接遍历0到和之间的数,一个是遍历和的因数。
坑点:注意0的情况(全0,末尾0),n个数相同的情况
代码如下(写的比较复杂orz):
1 #include <iostream> 2 #include <cstdio> 3 4 const int N = 105; 5 int a[N]; 6 7 int main(){ 8 int n, sum = 0; 9 char s[2]; 10 scanf("%d", &n); 11 gets(s); 12 for(int i = 0; i < n; i ++ ){ 13 scanf("%c",&a[i]); 14 a[i] -= '0'; 15 sum += a[i]; 16 } 17 bool f = true; 18 for(int i = 0; i < n; i ++ ){ 19 if(a[i] != 0){ 20 f = false; 21 break; 22 } 23 } 24 if(f){ 25 printf("YES\n"); 26 return 0; 27 } 28 bool f2 = true; 29 for(int i = 0; i < n - 1; i ++ ){ 30 if(a[i] != a[i+1]){ 31 f2 = false; 32 break; 33 } 34 } 35 if(f2){ 36 printf("YES\n"); 37 return 0; 38 } 39 bool flag = false; 40 for(int x = 2; sum / x >= 1 && x != n; x ++ ){ 41 if(sum % x == 0){ 42 int cnt = 0; 43 for(int i = 0, j = 0; j <= n;){ 44 if(cnt < sum / x){ 45 cnt += a[j++]; 46 } 47 else if(cnt == sum / x){ 48 if(j != n && a[j] != 0) 49 i = j, cnt = 0; 50 else if(j != n && a[j] == 0) 51 j ++ ; 52 else{ 53 flag = true; 54 break; 55 } 56 } 57 else if(cnt > sum / x){ 58 break; 59 } 60 } 61 if(flag) break; 62 } 63 if(flag) break; 64 } 65 if(flag) printf("YES\n"); 66 else printf("NO\n"); 67 return 0; 68 }
B
CF 1038D
链接:http://codeforces.com/problemset/problem/1038/D
题意:给一串数字,每个数可以减去它左右两边的数,求减到最后剩下的数的最大值
思路:分为两种情况,一种是有正有负的,那么答案直接是绝对值相加,一种是全为正或全为负(含0),那么答案直接是绝对值相加的总和,减去离0最近的那个数的绝对值的两倍。
代码如下:(因为clion的原因不知道为什么用不了min
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 const int N = 5e5 + 10; 6 typedef long long LL; 7 int a[N]; 8 9 int min(int y, int x); 10 11 int main(){ 12 int n; 13 scanf("%d", &n); 14 int x = 0x3f3f3f3f; 15 LL sum = 0; 16 bool pos = false, neg = false; 17 if(n == 1){ 18 scanf("%d", &a[0]); 19 printf("%d", a[0]); 20 return 0; 21 } 22 else 23 for(int i = 0; i < n; i ++ ){ 24 scanf("%d", &a[i]); 25 if(a[i] >= 0) { 26 pos = true; 27 x = min(a[i], x); 28 sum += a[i]; 29 } 30 else if(a[i] <= 0){ 31 neg = true; 32 x = min(abs(a[i]), x); 33 sum += abs(a[i]); 34 } 35 } 36 if(neg && pos) 37 printf("%lld", sum); 38 else 39 printf("%lld", sum - 2 * x); 40 return 0; 41 } 42 43 int min(int y, int x) { 44 if(x > y) return y; 45 else return x; 46 }
C
CF 234C
链接:http://codeforces.com/problemset/problem/234/C
题意:给出一行温度,通过一系列变换要使得某个数之前(包括这个数)都小于零,之后的数都大于零,求最小变换次数。
思路:通过计数存下当前数及当前数以前有多少个小于零和大于零的数,变换次数就等于该数后面小于零的数的个数加上该数前面大于零的数的个数。
注意此题需要用到文件读入输出。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 const int N = 1e5 + 10; 8 int a[N], sump[N], sumn[N]; 9 10 int main(){ 11 freopen("input.txt", "r", stdin); 12 freopen("output.txt", "w", stdout); 13 int n; 14 scanf("%d", &n); 15 //sump[0] = 0; 16 //sumn[0] = 0; 17 for(int i = 1; i <= n ; i ++ ){ 18 scanf("%d", &a[i]); 19 if(a[i] > 0){ 20 sump[i] = sump[i-1] + 1; 21 sumn[i] = sumn[i-1]; 22 } 23 else if(a[i] < 0){ 24 sumn[i] = sumn[i-1] + 1; 25 sump[i] = sump[i-1]; 26 } 27 else{ 28 sump[i] = sump[i-1] + 1; 29 sumn[i] = sumn[i-1] + 1; 30 } 31 } 32 int minn = 0x3f3f3f3f; 33 for(int i = 1; i < n ; i ++){ 34 int x = sump[i] + sumn[n] - sumn[i]; 35 minn = min(minn, x); 36 } 37 printf("%d", minn); 38 return 0; 39 }
G
CF 1206B
题意:给一行数,通过进行加一减一的操作使这行数的乘积为1
思路:计算该数与-1和1的距离,离谁近就变为谁,累加上加减一的次数,记录转化为-1的个数以及0的个数。最后若-1为奇数,则考虑通过将0转变成-1或将一个-1再加2次成为1。
注意答案需要开long long
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 const int N = 1e5 + 10; 8 int a[N]; 9 10 int main(){ 11 int n; 12 scanf("%d", &n); 13 int flag = 0;//记录-1的个数 14 int f = 0;//记录0的个数 15 long long ans = 0; 16 for(int i = 0; i < n ; i ++){ 17 scanf("%d", &a[i]); 18 int x = abs(a[i] - 1); 19 int y = abs(a[i] + 1); 20 if(a[i] == 0) 21 f++; 22 else if(x < y){ 23 ans += x; 24 } 25 else { 26 ans += y; 27 flag ++; 28 } 29 } 30 if(flag % 2 == 1){ 31 if(f) 32 ans += f; 33 else 34 ans = ans + 2; 35 } 36 else 37 ans += f; 38 printf("%lld", ans); 39 return 0; 40 }
H
CF 1245B
题意:给出对手的石头剪刀布顺序,给出己方每种手势的总数,问是否能赢过对手(赢的次数大于向上取整的n/2),如果可以写出出手势的顺序。
思路:先判断能不能赢,然后先把可以赢的填进对应的场次,再把剩下的abc分配去输的场合。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <string.h> 5 #include <cmath> 6 using namespace std; 7 const int N = 110; 8 char aa[N], bb[N]; 9 10 int main(){ 11 int t; 12 scanf("%d", &t); 13 while(t --){ 14 int n; 15 scanf("%d", &n); 16 char str[2]; 17 int a, b, c, r = 0, p = 0, s = 0; 18 scanf("%d %d %d", &a, &b, &c); 19 scanf("%c", &str[0]); 20 for(int i = 0; i < n; i ++ ){ 21 scanf("%c", &aa[i]); 22 if(aa[i] == 'R') r++; 23 else if(aa[i] == 'P') p++; 24 else s++; 25 } 26 scanf("%c", &str[0]); 27 int ans1 = 0, ans2 = 0, ans3 = 0; 28 ans1 += min(a, s); 29 ans2 += min(b, r); 30 ans3 += min(c, p); 31 int ans = ans1 + ans2 + ans3; 32 int x = ceil(double(n) / 2.0); 33 memset(bb, 0, sizeof bb); 34 if(ans >= x){ 35 printf("YES\n"); 36 for(int i = 0; i < n ; i ++ ){ 37 if(aa[i] == 'S' && ans1) 38 bb[i] = 'R', ans1 --, a--; 39 else if(aa[i] == 'R' && ans2) 40 bb[i] = 'P', ans2 --, b--; 41 else if(aa[i] == 'P' && ans3) 42 bb[i] = 'S', ans3 --, c--; 43 } 44 for(int i = 0; i < n ; i ++ ){ 45 if(bb[i] != 0) 46 printf("%c", bb[i]); 47 else{ 48 if(a) putchar('R'), a --; 49 else if(b) putchar('P'), b --; 50 else if(c) putchar('S'), c --; 51 } 52 } 53 cout<<endl; 54 } 55 else 56 cout<<"NO"<<endl; 57 } 58 return 0; 59 }
一以贯之的努力 不得懈怠的人生 每天的微小积累会决定最终结果 ————————裴之
欢迎加我QQ:1136244161一起讨论,共同进步