Codeforces_812
A. 每条人行道有六条车道会撞到。
#include<bits/stdc++.h> using namespace std; int a[4],b[4],c[4],d[4]; int main() { ios::sync_with_stdio(0); for(int i = 0;i < 4;i++) cin >> a[i] >> b[i] >> c[i] >> d[i]; int flag = 0; for(int i = 0;i < 4;i++) { if(!d[i]) continue; if(a[i] || b[i] || c[i] || a[(i+1)%4] || b[(i+2)%4] || c[(i+3)%4]) flag = 1; } if(flag) cout << "YES" << endl; else cout << "NO" << endl; return 0; }
B.dp,注意最后一层增加的时间不一样。
#include<bits/stdc++.h> using namespace std; int n,m,dp[2][20] = {0}; string s[20]; int main() { ios::sync_with_stdio(0); cin >> n >> m; for(int i = 1;i <= n;i++) { cin >> s[i]; s[i] = " "+s[i]; } int t; for(t = 1;t <= n;t++) { int flag = 0; for(int j = 1;j <= m+2;j++) { if(s[t][j] == '1') flag = 1; } if(flag) break; } if(t == n+1) { cout << 0 << endl; return 0; } dp[0][n+1] = -1; dp[1][n+1] = 1e9; for(int i = n;i >= t;i--) { int l = m+2; int r = 1; for(int j = m+2;j >= 1;j--) { if(s[i][j] == '1') l = j; } for(int j = 1;j <= m+2;j++) { if(s[i][j] == '1') r = j; } if(i == t) { cout << min(dp[0][i+1]+r,dp[1][i+1]+m+3-l) << endl; return 0; } dp[0][i] = min(dp[1][i+1]+m+2,dp[0][i+1]+2*(r-1)+1); dp[1][i] = min(dp[0][i+1]+m+2,dp[1][i+1]+2*(m+2-l)+1); } return 0; }
C.二分个数,注意long long。
#include<bits/stdc++.h> using namespace std; int n,s; long long a[100005],b[100005]; bool ok(int x) { for(int i = 1;i <= n;i++) b[i] = a[i]+(long long)x*i; sort(b+1,b+1+n); long long sum = 0; for(int i = 1;i <= x;i++) sum += b[i]; return sum <= s; } int main() { ios::sync_with_stdio(0); cin >> n >> s; for(int i = 1;i <= n;i++) cin >> a[i]; int l = 0,r = n; while(l < r) { int mid = (l+r+1)/2; if(ok(mid)) l = mid; else r = mid-1; } for(int i = 1;i <= n;i++) b[i] = a[i]+(long long)l*i; sort(b+1,b+1+n); long long sum = 0; for(int i = 1;i <= l;i++) sum += b[i]; cout << l << " " << sum << endl; return 0; }
D.建一个有向图,前面的requests组成的是森林或树,再加一个后,若形成了环,则x和x的子孙都会cry,否则没有人会cry。
对于1e5的queries,我们先预处理每个节点的子孙个数和和dfs序,然后判断就简单了。
#include<bits/stdc++.h> using namespace std; int n,m,k,q,cnt = 0,pre[100005] = {0},l[100005],r[100005],ok[100005] = {0},sum[100005]; vector<int> v[100005]; void dfs(int now) { ++cnt; l[now] = cnt; sum[now] = 1; for(int i = 0;i < v[now].size();i++) { int t = v[now][i]; dfs(t); sum[now] += sum[t]; } r[now] = cnt; } int main() { ios::sync_with_stdio(0); cin >> n >> m >> k >> q; while(k--) { int x,y; cin >> x >> y; if(pre[y] != 0) { v[pre[y]].push_back(x); ok[x] = 1; } pre[y] = x; } for(int i = 1;i <= n;i++) { if(!ok[i]) dfs(i); } while(q--) { int x,y; cin >> x >> y; if(pre[y] && l[x] <= l[pre[y]] && r[pre[y]] <= r[x]) cout << sum[x] << endl; else cout << 0 << endl; } return 0; }
E.普通nim游戏判断过程为每堆石子个数的异或。若增加一个可以增加石子的操作,结果相同,因为一个人加的另一个人可以减去相同数量。我们建树,把跟叶子节点向上相差偶数个节点的点作为堆,其余的作为可以增加的石子。那么判断过程为这些堆的异或。ok为0则成立,我们现在要使ok变为0。
根据异或性质,在两类节点之间可以成立的交换操作为ok^a[i]^b[i]==0的两个点。
另外,若ok已经为0,我们可以进行节点同类中交换。
#include<bits/stdc++.h> using namespace std; int n,a[200005],h[200005]; map<int,int> mp; vector<int> v[200005]; void dfs(int now) { int x = 0; for(int i = 0;i < v[now].size();i++) { int t = v[now][i]; dfs(t); x = max(h[t],x); } h[now] = x+1; } int main() { ios::sync_with_stdio(0); cin >> n; for(int i = 1;i <= n;i++) cin >> a[i]; for(int i = 2;i <= n;i++) { int x; cin >> x; v[x].push_back(i); } dfs(1); int ok = 0,cnt1 = 0; for(int i = 1;i <= n;i++) { if(h[i]%2) { ok ^= a[i]; cnt1++; mp[a[i]]++; } } int cnt2 = n-cnt1; long long ans = 0; if(ok == 0) ans = (long long)cnt1*(cnt1-1)/2+(long long)cnt2*(cnt2-1)/2; for(int i = 1;i <= n;i++) { if(h[i]%2 == 0) ans += mp[ok^a[i]]; } cout << ans << endl; return 0; }