Codeforces Round #428 (Div. 2) 题解
题目链接:http://codeforces.com/contest/839
A. Arya and Bran
题意:每天给你一点糖果,如果大于8个,就只能给8个,剩下的可以存起来,小于8个就可以全部给完
解法:水题,按照题意模拟一下即可。
#include <bits/stdc++.h> using namespace std; int n, k, a[110]; int main() { cin>>n>>k; int s = 0; for(int i=1; i<=n; i++){ int x; cin >> x; s += x; x = min(s, 8); s -= x; k -= x; if(k<=0){ cout<<i<<endl; return 0; } } cout<<-1<<endl; return 0; }
B. Game of the Rows
题意:将n批人安排进题目里给出的那种n行座位中,不同批的人只能隔着坐,问能不能安排下这些人
解法:首先必然先安排大于等于3人的批次,将他们尽量安排在中间四连座的座位,安排不下了再安排在旁边两连座的,若也安排不下了,则必然输出NO,然后在安排剩余2个人的批次,先尽量安排在两连座的,若安排不下了则安排在中间四连座的,并且还可以安排边上坐一个人,若也安排不下,则将两个人拆开当作一个人去安排,最后判断座位够不够剩余1个人的批次即可
#include <bits/stdc++.h> using namespace std; const int maxn = 10010; int n, k, a[maxn], have[5], sum[5]; int main() { while(~scanf("%d%d",&n,&k)) { int flag=1; memset(sum,0,sizeof(sum)); memset(have,0,sizeof(have)); have[2]=2*n; have[4]=n; for(int i=0; i<k; i++) scanf("%d", &a[i]); for(int i=0; i<k; i++){ while(a[i]>=3){ if(have[4]){ have[4]--; a[i]-=4; } else if(have[2]){ have[2]--; a[i]-=2; } else{ flag=0; puts("NO"); break; } } sum[a[i]]++; } while(sum[2]){ if(have[2]){ have[2]--; sum[2]--; } else if(have[4]){ have[4]--; sum[2]--; have[1]++; } else{ sum[2]--; sum[1]+=2; } } if(flag){ if(sum[1]>have[1]+have[2]+have[4]*2){ puts("NO"); } else{ puts("YES"); } } } return 0; }
C. Journey
题意:给你一颗树,设每两个节点间距离为1,从1开始,让你求这棵树的路程的期望
解法:基础期望DP,逆推即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; struct edge{ int to,next; }E[maxn*2]; int head[maxn],edgecnt, n; void init(){ memset(head,-1,sizeof(head)); edgecnt=0; } void add(int u, int v){ E[edgecnt].to=v,E[edgecnt].next=head[u],head[u]=edgecnt++; } double dp[maxn]; void dfs(int u, int fa){ int cnt=0; dp[u] = 0; for(int i=head[u];~i;i=E[i].next){ int v = E[i].to; if(v == fa) continue; dfs(v, u); dp[u] += dp[v]; cnt++; } if(cnt!=0) dp[u] = dp[u]/cnt+1; } int main() { cin >> n; init(); for(int i=1; i<n; i++){ int u, v; scanf("%d %d", &u,&v); add(u,v); add(v,u); } dfs(1,-1); printf("%.10f\n", dp[1]); return 0; }
D. Winter is here
题意:如果一个子序列的GCD为1,那么这个子序列的价值为0,否则子序列价值为子序列长度*子序列GCD。给出n个数,求这n个数所有子序列的价值和
解法:
#include <bits/stdc++.h> using namespace std; const int maxn = 1000010; const int mod = 1e9+7; typedef long long LL; LL cnt[maxn],sum[maxn]; LL qsm(LL a, LL n){ LL ret=1; while(n){ if(n&1) ret=ret*a%mod; a=a*a%mod; n/=2; } return ret; } int main() { int n; LL x, mx=0; scanf("%d", &n); for(int i=1; i<=n; i++){ scanf("%lld", &x); mx = max(mx, x); cnt[x]++; } LL ans=0; for(int i=mx; i>=2; i--){ x=0; for(int j=i; j<=mx; j+=i){ sum[i]-=sum[j]; x+=cnt[j]; } sum[i]+=x*qsm(2LL,x-1)%mod; ans=((ans+sum[i]*i)%mod+mod)%mod; } printf("%lld\n", ans); return 0; }
E. Mother of Dragons
题意:给了一个图,然后给了一个值,你可以把这个值分给有些点,对于一条边 u,v,价值是u的值乘以v的值吗,问如何分配可以使得值最大,问最大的值是多少。
解法:参考题解:http://www.cnblogs.com/FxxL/p/7357221.html
可以证明选最大团是最优解,所以套上求解最大团的模板就可以了。
#include <bits/stdc++.h> using namespace std; #define N 110 //点从1到n bool g[N][N]; int p, k; int que[N],cnt[N];//cnt[i]记录大于等于i的点集的最大团点数,i点可以不在其中 int ans;//ans为最终最大团点数 bool dfs(int pos,int num,int n) { for(int i=pos+1; i<=n; i++) { if(num+cnt[i]<=ans) return 0; //如果取i 但是cnt[i]也就是 >= i 的最大团点数 + 已经取了的点数还小于 ans, 剪枝 if(g[pos][i]) { int j; for(j=0; j<num; ++j) if(!g[i][ que[j] ]) break; if(j==num) { que[num]=i; if(dfs(i,num+1,n)) return 1; } } } if(num>ans)//因为每填加一个点最多使最大团数+1,后面的搜索就没有意义了 { ans=num; return 1;//如果需要输出方案的话,此时的que内的点即为方案 } return 0; } void solve(int n) { ans=0; for(int i=n; i>=1; i--) { que[0]=i; dfs(i,1,n); cnt[i]=ans; } } int main() { scanf("%d%d",&p,&k); for(int i=1; i<=p; i++){ for(int j=1; j<=p; j++){ scanf("%d", &g[i][j]); } } solve(p); double sum = 1.0*(ans)*(ans-1)/2*(1.0*k/ans)*(1.0*k/ans); printf("%.10f\n", sum); return 0; }