codeforces round #420 div2
A:暴力枚举
模拟
#include<bits/stdc++.h> using namespace std; const int N = 60; int n; int a[N][N]; int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) scanf("%d", &a[i][j]); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) if(a[i][j] != 1) { bool flag = false; for(int x = 1; x <= n; ++x) if(x != i) for(int y = 1; y <= n; ++y) if(y != j) if(a[i][j] == a[x][j] + a[i][y]) { flag = true; break; } if(!flag) { puts("No"); return 0; } } puts("Yes"); return 0; }
B:其实我们发现,枚举纵坐标就能枚举出直线上所有的点,然后里面的价值可以O(1)算出,于是枚举纵坐标即可。
模拟
#include<bits/stdc++.h> using namespace std; int m, b; int main() { long long ans = 0; scanf("%d%d", &m, &b); for(long long y = 0; y <= b; ++y) { long long x = m * b - m * y, tot = (1ll + x) * x / 2ll * (y + 1ll) + (1ll + y) * y / 2ll * (x + 1ll); ans = max(ans, tot); } printf("%lld\n", ans); return 0; }
C:这道题挺奥妙的。
脑洞
我们可以维护一个pq,当当前的值和pq的最小值不等时说明要调整。那么我们得问题就在于如何记录当前的值。然后发现这样不好做,因为调整后所有值都变了,那么我们换着一种思路,我们记录到第一个不符合的值之前有多少个符合的。当每次出现不符合的值时,把这个值赋成1,然后累加。每次删除时,我们只要减一,如果减到零了,说明需要调整,那么之前不符合的也符合了,所以之前那些值是没有用的,这样就完成了。
#include<bits/stdc++.h> using namespace std; const int N = 300010; int n, ans, cnt; priority_queue<int, vector<int>, greater<int> > q; int main() { scanf("%d", &n); bool flag = true; for(int i = 1; i <= 2 * n; ++i) { char opt[10]; scanf("%s", opt); if(opt[0] == 'a') { int pos; scanf("%d", &pos); if(!q.empty() && pos > q.top()) cnt = 1; //如果不行了 ,那么肯定需要排序,之前不算 else if(cnt) ++cnt; //如果之前不行,现在行,计算可以不用调整的次数 q.push(pos); } if(opt[0] == 'r') { q.pop(); if(cnt) { --cnt; //累计在不行之前能减的次数 if(cnt == 0) ++ans; } } } printf("%d\n", ans); return 0; }
题解的方法是维护一个栈,每次remove时看是否和应该remove的值相等,相等就弹出,不等就ans+1,把所有元素弹出。这样为什么是对的呢?因为如果当前的数和栈顶相同,那么就是可以的,否则就需要调整。调整完了之后之前的数是有序的,也就不用再调整了,只有进来不可行的才需要调整。(我也理解的不是很透彻,还是上面那个方法直观)
#include<bits/stdc++.h> using namespace std; int n, ans, now = 1; stack<int> st; int main() { scanf("%d", &n); for(int i = 1; i <= 2 * n; ++i) { char opt[10]; scanf("%s", opt); if(opt[0] == 'a') { int pos; scanf("%d", &pos); st.push(pos); } if(opt[0] == 'r') { if(!st.empty()) { if(now == st.top()) st.pop(); else { ans++; while(!st.empty()) st.pop(); } } ++now; } } printf("%d\n", ans); return 0; }
D:这道题写的时候出题人说样例挂了,还有这种操作。。。
最短路
我们发现,只有横纵坐标有一个相差<=2时可以走过去,那么我们就可以考虑建图。这里要分类讨论一下边权的情况,还有终点是否亮。代码里都有了,然后跑最短路就行,可以用deque也可以用dijiestra,dijiestra跑得还挺快。记住不能把边存下来,有n^2条边。
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; const int N = 10010; struct data { int x, y; } a[N]; int n, m, k; priority_queue<PII, vector<PII>, greater<PII> >q; int d[N], used[N], Q[N]; bool flag = true; bool cp(data x, data y) { return x.x == y.x ? x.y < y.y : x.x < y.x; } void dijiestra() { memset(used, 0, sizeof(used)); for(int i = 2; i <= k; ++i) d[i] = 1 << 29; q.push(PII(0, 1)); while(!q.empty()) { PII x = q.top(); q.pop(); int u = x.second; if(used[u]) continue; used[u] = 1; for(int i = 1; i <= k; ++i) if(i != u) if(abs(a[i].x - a[u].x) <= 2 || abs(a[i].y - a[u].y) <= 2) { int w = 1; if((abs(a[i].x - a[u].x) == 1 || abs(a[i].y - a[u].y) == 1) && (a[i].x - a[u].x == 0 || a[i].y - a[u].y == 0)) w = 0; if(a[i].x == n && a[i].y == m && !flag) { w = 1; if((abs(a[i].x - a[u].x) == 2 || abs(a[i].y - a[u].y) == 2) && (abs(a[i].x - a[u].x) >= 2 && abs(a[i].y - a[u].y) >= 2)) w = 1 << 29; } if(d[i] > d[u] + w) { d[i] = d[u] + w; q.push(PII(d[i], i)); } } } } int main() { scanf("%d%d%d", &n, &m, &k); for(int i = 1; i <= k; ++i) scanf("%d%d", &a[i].x, &a[i].y); sort(a + 1, a + k + 1, cp); if(a[k].x != n || a[k].y != m) { flag = false; a[++k].x = n; a[k].y = m; } dijiestra(); printf("%d\n", d[k] >= 1 << 29 ? -1 : d[k]); return 0; }
E:昨天晚上以为这道题组合搞搞就行了。。。
矩阵快速幂
dp:dp[i][x]=dp[i-1][x-1]+dp[i-1][x]+dp[i-1][x+1] 边界不讨论了。
然后这是标准的矩阵快速幂形式,那么对于每条线段构造矩阵,最后一条线段的终点要设成k,初值dp[0][0]=1,输出dp[k][0]。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 110; const ll mod = 1000000007; struct mat { ll a[16][16]; } l; struct data { ll a, b; int c; } a[N]; int n; ll k; mat operator * (mat A, mat B) { mat ret; memset(ret.a, 0, sizeof(ret.a)); for(int i = 0; i <= 15; ++i) for(int j = 0; j <= 15; ++j) for(int k = 0; k <= 15; ++k) ret.a[i][j] = (ret.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod; return ret; } mat power(mat x, ll t) { mat ret; memset(ret.a, 0, sizeof(ret.a)); for(int i = 0; i <= 15; ++i) ret.a[i][i] = 1; for(; t; t >>= 1, x = x * x) if(t & 1) ret = x * ret; return ret; } int main() { cin >> n >> k; for(int i = 1; i <= n; ++i) scanf("%lld%lld%d", &a[i].a, &a[i].b, &a[i].c); a[n].b= k; l.a[0][0] = 1; for(int i = 1; i <= n; ++i) { mat x; memset(x.a, 0, sizeof(x.a)); for(int j = 0; j <= a[i].c; ++j) { if(j > 0) x.a[j][j - 1] = 1; x.a[j][j] = 1; if(j < a[i].c) x.a[j][j + 1] = 1; } l = power(x, a[i].b - a[i].a) * l; } printf("%lld\n", l.a[0][0]); return 0; }