codeforces round #428 div2
A:暴力模拟,能加就加,如果累计到了8就加上,每次累积
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; int main() { int n,k ,cnt = 0; scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) { int x; scanf("%d", &x); cnt += x; if(cnt >= 8) { k -= 8; cnt -= 8; } else { k -= cnt; cnt = 0; } if(k <= 0) { printf("%d\n", i); return 0; } } puts("-1"); return 0; }
B:模拟,情况有点多,先每四个人分配位置,四人座不够分配二人座,然后每两个人分配,两人坐没了分配四人座,分配四人座的时候每次统计+1,如果两人四人都没了两个四人座剩下的可以给两个人坐在边上,剩下一个人就把两人坐四人座分配,两人座可以做一个人,四人座可以做两个人,之前统计+1可以坐一个人
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, k; int a[N]; int main() { scanf("%d%d", &n, &k); int cnt1 = n * 2, cnt2 = n, one = 0; for(int i = 1; i <= k; ++i) { scanf("%d", &a[i]); int x = a[i] / 4; a[i] %= 4; if(cnt2 >= x) cnt2 -= x; else { x -= cnt2; cnt2 = 0; if(cnt1 >= 2 * x) cnt1 -= 2 * x; else { puts("NO"); return 0; } } } for(int i = 1; i <= k; ++i) { if(a[i] == 0) continue; int x = a[i] / 2; a[i] %= 2; if(cnt1 >= x) cnt1 -= x; else { x -= cnt1; cnt1 = 0; if(cnt2 >= x) { cnt2 -= x; one += x; } else if(one >= x * 2) { one -= x * 2; } else { puts("NO"); return 0; } } } one += 2 * cnt2 + cnt1; for(int i = 1; i <= k; ++i) { if(a[i] == 0) continue; --one; if(one < 0) { puts("NO"); return 0; } } puts("YES"); return 0; }
C:一个比较简单的概率dp,每次dp[v]=dp[u]/(size[u]-(last == 0)),如果是根节点last=0没有前继,概率就是度数,否则度数-1,然后叶子结点的概率乘上步长就是答案
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 100010; int n; double ans; double dp[N]; vector<int> G[N]; void dfs(int u, int last, int dis) { if(G[u].size() == 1) ans += dp[u] * (double)dis; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == last) continue; dp[v] = dp[u] * 1.0 / (double)(G[u].size() - (last != 0)); dfs(v, u, dis + 1); } } int main() { scanf("%d", &n); dp[1] = 1.0; for(int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } dfs(1, 0, 0); // for(int i = 1; i <= n; ++i) printf("dp[%d]=%.6f\n", i, dp[i]); printf("%.8f\n", ans); return 0; }
D:一个很好的题,我们用容斥原理来做,设cnt[i]表示能整除i的a[i]的个数,ans[i]表示gcd为i的子序列的答案,我们发现直接计算ans似乎有些困难,但是我们可以容斥,我们放宽条件,先找出gcd能整除i的子序列的人的总和的可能的总数,是C(n,1)*1+C(n,2)*2+C(n,3)*3+...+C(n,n)*n,意思是n个人选1个人的方案数*1个人,n个人选两个人*两个人,统计了所有子序列的总人数,然后我们加一项C(n,0)*0,然后倒序相加,就得到了n*(C(n,0)+C(n,1)+...+C(n,n))/2=n*2^n/2=n*2^n-1,这是gcd是n的倍数的答案,然后根据容斥原理,我们把ans[i*2],ans[i*3]...减去,剩下的就是答案
这其实跟莫比乌斯反演挺像的,就是限制太强就用容斥弱化一下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N = 200010, mod = 1000000007; int n; int a[N], has[N * 10], cnt[N * 10]; long long ans[N * 10]; long long answer; inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } long long power(long long x, long long t) { long long ret = 1; for(; t; t >>= 1, x = x * x % mod) if(t & 1) ret = ret * x % mod; return ret; } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) { a[i] = read(); ++has[a[i]]; } for(int i = 2; i <= 1000000; ++i) for(int j = i; j <= 1000000; j += i) cnt[i] += has[j]; for(int i = 1000000; i >= 2; --i) if(cnt[i] > 0) { ans[i] = (long long)cnt[i] * (long long)power(2, cnt[i] - 1) % mod; for(int j = i * 2; j <= 1000000; j += i) ans[i] -= ans[j]; answer = (answer + (long long)i * ans[i]) % mod; } printf("%lld\n", (answer % mod + mod) % mod); return 0; }