A. Grandma Laura and Apples
题意:n 和 p 分别表示有n次购买以及苹果的单价p;下面n行,half表示购买一半的苹果,halfplus表示购买一半的苹果再赠送半个苹果,n次购买之后苹果没有剩余,问一共卖了多少钱;
思路:因为最后苹果没有剩余,即为0,所以我们从最后一次购买进行倒推,half — 直接*2,halfplus — 先+0.5再*2;
#include<bits/stdc++.h> #define ll __int64 int n, p; char s[20]; int a[50]; int main() { scanf("%d%d", &n, &p); ll ans = 0; for(int i = 1;i<=n;i++) { scanf("%s", s); int len = strlen(s); if(len == 4) a[i] = 0; else a[i] = 1; } double k = 0; for(int i = n;i>=1;i--) { if(a[i]) { k = (k+0.5)*2.0; ll t = k/2.0*p; ans += t; } else { k = k*2.0; ll t = k/2.0*p; ans += t; } } printf("%I64d\n", ans); return 0; }
B. Alice, Bob, Two Teams
题意:有n个物品,给出每个物品的价值,以及一个字符串表示对应的物品属于A或B,可以对字符串的某个前缀或者后缀进行翻转(即A变B,B变A),求B所能获得的最大价值;
思路:记录原始状态下A和B的前缀价值,然后进行遍历,所谓翻转就是将A和B的价值呼唤;
#include<bits/stdc++.h> typedef __int64 ll; using namespace std; const int maxn = 500000+10; ll atmp[maxn], btmp[maxn]; int num[maxn]; char s[maxn]; int n; int main() { scanf("%d", &n); for(int i = 1;i<=n;i++) scanf("%d", &num[i]); scanf("%s", s+1); memset(atmp, 0, sizeof atmp); memset(btmp, 0, sizeof btmp); for(int i = 1;i<=n;i++) { if(s[i] == 'A') atmp[i] = atmp[i-1] + num[i]; else atmp[i] = atmp[i-1]; if(s[i] == 'B') btmp[i] = btmp[i-1] + num[i]; else btmp[i] = btmp[i-1]; } ll maxx = -1; for(int i = 1;i<=n;i++) { maxx = max(maxx, btmp[n] - btmp[i] + atmp[i]); maxx = max(maxx, btmp[i] + atmp[n] - atmp[i]); } printf("%I64d\n", maxx); return 0; }
题意:给出n个字符串,将它们按字典序输出;
#include<bits/stdc++.h> using namespace std; const int maxn = 50000+10; int n; string s[maxn]; bool cmp(string a, string b) { return a+b < b+a; } int main() { scanf("%d", &n); for(int i = 0;i<n;i++) cin>>s[i]; sort(s, s+n, cmp); for(int i = 0;i<n;i++) cout<<s[i]; printf("\n"); return 0; }
题意:给你n个数,找出最长的子序列,使子序列的最小公倍数小于等于m,输出该子序列在原序列中的对应顺序;
思路:最小公倍数小于等于m,那么子序列中的数必定也小于等于m,我们先记录原序列中小于等于m的数字的个数,然后遍历i = 1 ~ i = m,对每一个 i 遍历其倍数 j(当然j <= m) ,然后将原序列中 i 的个数加到 j 数组中,表示当公倍数为 j 时,其因数 i 有多少个;那么最后得到的 j 数组即为当公倍数为 j 时,组成的子序列的长度;
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; int a[maxn]; int cnt[maxn], tmp[maxn]; int n, m; int main() { scanf("%d%d", &n, &m); memset(cnt, 0, sizeof cnt); memset(tmp, 0, sizeof tmp); for(int i = 1;i<=n;i++) { scanf("%d", &a[i]); if(a[i] <= m) cnt[a[i]]++; } for(int i = 1;i<=m;i++) { for(int j = i;j<=m;j+=i) { if(cnt[i]) tmp[j] += cnt[i]; } } int maxx = -1; int k; for(int i = 1;i<=m;i++) { if(maxx < tmp[i]) { maxx = tmp[i]; k = i; } } printf("%d %d\n", k, maxx); for(int i = 1;i<=n;i++) { if(k % a[i] == 0) printf("%d ", i); } printf("\n"); return 0; }
题意:给出n个数,每个数字有无限个,求取k个数能组成的和,按从小到大输出;
思路:将数组从小到大进行排序,然后都减去最小的那个数,dp[i]表示组成和为 i 的数字个数,当个数小于 k 时,不够的个数就由 a[1] 来补齐,因为此时 a[1] 的值为0,所以不会改变 i 的值;最后输出答案时,要将之前减去的 a[1] 的值再加回来,即 i + (k - dp[i]) * a[1] + dp[i] * a[1] = i + k * a[1];
#include<cstdio> #include<iostream> #include<algorithm> #define inf 999999999 using namespace std; const int maxn = 1100; int n, k; int a[maxn]; int dp[maxn*maxn]; int main() { scanf("%d%d", &n, &k); for(int i = 1;i<=n;i++) scanf("%d", &a[i]); sort(a+1, a+n+1); int t = a[1]; int num = unique(a+1, a+n+1)-(a+1); //加一个优化,将相同的数字排除; for(int i = 2;i<=num;i++) a[i] -= t; for(int i = 1;i<=a[num]*k;i++) dp[i] = inf; dp[0] = 0; for(int i = 2;i<=num;i++) { for(int j = a[i];j<=a[i]*k;j++) dp[j] = min(dp[j], dp[j-a[i]]+1); } for(int i = 0;i<=a[num]*k;i++) { if(dp[i] <= k) printf("%d ", i+t*k); } printf("\n"); return 0; }
题意:判断一个矩阵是否为魔法矩阵,魔法矩阵的定义:a[i][i] 上的数均为0,其余的数字关于a[i][i] 对角线对称,
并且,对于任意的 k (1 ≤ k ≤ n) 满足 a[i][j] ≤ max(a[i][k], a[j][k]);
思路:前面两个条件都好判断,关键是第三个,对于a[i][j],我们分别找出第 i 行和第 j 行比a[i][j] 小的数,如果两行中比a[i][j]小的数位于同一列(即k相同的时候,此时,a[i][k] 和 a[j][k] 都比a[i][j]),那么不符合条件,就不是魔法矩阵;
我们用bitset来储存第 i 行比a[i][j] 小的数为哪几列;
#include<cstdio> #include<bitset> #include<algorithm> using namespace std; const int maxn = 2600; int n; int map[maxn][maxn]; bitset<maxn>b[maxn]; struct node { int x, y; int w; }a[maxn*maxn]; bool cmp(node a, node b) { return a.w < b.w; } int main() { scanf("%d", &n); bool flag = true; int cnt = 0; for(int i = 1;i<=n;i++) { for(int j = 1;j<=n;j++) { scanf("%d", &map[i][j]); if(i == j && map[i][j] != 0) flag = false; a[cnt].x = i, a[cnt].y = j; a[cnt].w = map[i][j]; cnt++; } } if(!flag) { printf("NOT MAGIC\n"); return 0; } for(int i = 1;i<=n;i++) { for(int j = 1;j<=n;j++) { if(map[i][j] != map[j][i]) { printf("NOT MAGIC\n"); return 0; } } } sort(a, a+cnt, cmp); int t = 0; for(int i = 0;i<cnt;i++) { int x = a[i].x, y = a[i].y; while(t < cnt && a[t].w < a[i].w) { b[a[t].x][a[t].y] = 1; b[a[t].y][a[t].x] = 1; t++; } if((b[x] & b[y]).any()) //any()用来计算1的个数; { printf("NOT MAGIC\n"); return 0; } } printf("MAGIC\n"); return 0; }