Codeforces Round #219 (Div. 2) 题解
A.Collecting Beats is Fun
题意:有4*4的矩阵,矩阵上有0-9的数字,3表示在第3秒的时候要按他,一只手一秒最多按k个,问能不能把规定的都按完
思路:直接模拟
代码:
#include <bits/stdc++.h> using namespace std; map<int, int> mp; int main() { int n; scanf("%d", &n); for(int i = 1; i <= 4; i++) { for(int j = 1; j <= 4; j++) { char ch; cin>>ch; if('0' <= ch && ch <= '9') mp[ch - '0']++; } } bool ok=true; for(int i = 0; i <= 9; i++) { if(mp[i] > 2 * n) { ok =false; break; } } if(ok) puts("YES"); else puts("NO"); return 0; }
B.Making Sequences is Fun
题意:s(n)表示n的位数,现在有w元,向数列中加入数x,要花费s(x)*k元现在数列中的第一个数是m,构造一个m,m+1,m+2…这样的数列,最长为多长
思路:先求出数列的长度,然后看与上一个10的次方还差多少,如果可以整除的话直接跳上去,一直到不能减为止
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; int getlen(LL x) { int res = 0; while(x) { x /= 10; res ++; } return res; } int main() { LL w, m, k; scanf("%lld%lld%lld", &w, &m, &k); w /= k; int len = getlen(m); // printf("test %d\n",len); LL num = 1; for(int i = 1; i <= len; i++) num *= 10; LL ans = 0; for(int i = len; ; i++) { if(w - (num - m) * i >= 0) { w -= i * (num - m); ans += num - m; m = num; num *= 10; } else { ans += w / i; break; } } cout<< ans <<endl; return 0; }
C. Counting Kangaroos is Fun
题意:有n(5e5)只袋鼠,每只袋鼠都有一个体重,每只袋鼠中的口袋可以装比它体重小于等于一半的袋鼠,只能装一只,被装进去的袋鼠不能装东西,装到口袋中的袋鼠不会被看到,问最少能看到几只袋鼠;
思路:因为最多装n/2只袋鼠,所以设置两个指针i=1,j=n/2,一只遍历,能装几个装几个
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=5e5+7; int a[maxn]; int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } sort(a+1,a+1+n); int ans=0; for(int i=1,j=n/2+1;i<=n/2&&j<=n;){ if(a[i]*2<=a[j]){ ans++;i++;j++; } else j++; } printf("%d\n",n-ans); return 0; }
D. Counting Rectangles is Fun
题意:有一个n*m(40)的01矩阵,有q次询问,每次询问矩形(a,b)(c,d)中有多少个全0的矩形
思路:定义dp[i][j][p][q]为(i,j)到(p,q)中全0矩形的个数,维护一个数组num[i][j]表示,在[i][j]位置的数字左侧有多少个连续的0,在转移的时候需要先容斥一下,然后只需要计算包含右下角的0矩形个数,从下向上扫一下,加上即可以了
代码:
#include <bits/stdc++.h> using namespace std; int dp[45][45][45][45]; int a[45][45]; int num[45][45]; int n,m,Q; int main() { scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%1d",&a[i][j]); num[i][j]=num[i][j-1]; if(a[i][j])num[i][j]=0; else num[i][j]++; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(int p=i;p<=n;p++){ for(int q=j;q<=m;q++){ dp[i][j][p][q]=dp[i][j][p-1][q]+dp[i][j][p][q-1]-dp[i][j][p-1][q-1]; int res=q-j+1; for(int as=p;as>=i;as--){ res=min(res,num[as][q]); dp[i][j][p][q]+=res; } } } } } while(Q--){ int b,c,d,e; scanf("%d%d%d%d",&b,&c,&d,&e); printf("%d\n",dp[b][c][d][e]); } return 0; }
E. Watching Fireworks is Fun
题意:在一个长度为n(150000)的数轴上,有m(300)个烟花,每个烟花在ai的位置上,在ti秒放,假设站在x的位置上可以获得bi-abs(ai-x)的幸福值,每秒人移动的距离是d,人最开始可以在任何一个位置,每个烟花都要看,问最多获得多少幸福值。
思路:定义dp[i][j]表示前i个烟花放了以后,站在第j个位置可以获得的最大幸福值,那么dp[i][j]=max(dp[i-1][j+k*d]+b[i]-abs(a[i]-j));可以用一个单调队列维护来进行优化,如果新来的比队尾大,就可以弹出队尾,维护一个递减的单调队列,当前最优的一直在队首。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 150000 + 7; int n,m; LL d; LL dp[2][maxn]; LL a[305],b[305],t[305]; LL que[maxn]; int main() { scanf("%d%d%lld", &n, &m, &d); for(int i = 1; i <= m; i++) { scanf("%lld%lld%lld", &a[i], &b[i], &t[i]); } int now=0; LL pre = t[1]; for(int i = 1; i <= m; i++) { int k = 1; if(pre == t[i]) { for(int j = 1; j <= n; j++) { dp[now][j] = dp[now^1][j] + b[i] - abs(a[i] - j); } } else { int L = 1, R = 0; LL len = d * (t[i] - pre); pre = t[i]; for(int j = 1; j <= n; j++) { while(k <= n && k <= j + len) { while(L <= R && dp[now ^ 1][que[R]] < dp[now ^ 1][k]) R--; que[++ R] = k ++; } while(L <= R && j - len > que[L]) L++; dp[now][j] = dp[now ^ 1][que[L]] + b[i] - abs(a[i] - j); } } now ^= 1; } LL ans = -1e18; for(int i = 1; i <= n ;i ++) { ans = max(ans, dp[now ^ 1][i]); } cout<< ans <<endl; return 0; }