Codeforces Round #202 (Div. 2) 题解
A.Cinema Line
题意:游客去买票,游客只会拿25,50, 100的钱,刚开始售票处的钱为0,一张门票的价格是25,问你是否有零钱找给这n个游客
思路:记录现在有多少个25元和多少个50的,如果游客是25元的钱,不需要找钱,50时只能用25的钱找给游客,100时,可以用50+25或者3个25元的,尽量先用50的
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int a[maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int cnt=0,res=0; for(int i=1;i<=n;i++){ if(a[i]==25){ cnt++; } else if(a[i]==50){ res++; if(cnt){ cnt--; } else{ printf("NO\n"); return 0; } } else if(a[i]==100){ if(res&&cnt){ res--;cnt--; } else if(cnt>=3){ cnt-=3; } else{ printf("NO\n"); return 0; } } } printf("YES\n"); return 0; }
B.Color the Fence
题意:你知道刷每个1-9数字需要多少升颜料,你现在有v升颜料,问你能刷出来最大的数是多少
思路:数字越长越大,先用花费最少的数字尽可能的使答案边长,然后还会剩下一些燃料,在从高位开始,把高位数字尽可能的改大一点
代码:
C.Mafia
题意:有一种游戏,每次游戏都会有一个人做庄家,其他人做玩家,现在有n个人,他们都想做ai次玩家,问你最小需要玩多少次游戏
思路:二分答案,对于二分的mid,进行判断,让L取为n个玩家中的最大值,记n个人想做玩家的总和为sum,进行mid局游戏,有mid*(n-1)个玩家,判断sum与mid*(n-1)的关系
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e5+7; int n; LL a[maxn]; LL sum; bool check(LL x) { if((n-1)*x>=sum)return true; return false; } int main() { scanf("%d",&n); sum=0; LL maxe=-1; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); sum+=a[i]; maxe=max(maxe,a[i]); } LL L=maxe,R=0x3f3f3f3f3f3fLL; LL ans=0; while(L<=R){ LL mid=(L+R)>>1; if(check(mid)){ R=mid-1; ans=mid; } else L=mid+1; } cout<<ans<<endl; return 0; }
D.Apple Tree
题意:有一棵树,每个叶子节点都有一个权值,问你最少减多少权值可以是整颗树平衡,平衡的定义是一个点的所有儿子权值相等,一个非叶子节点的权值等于他子孩子中叶子节点的权值和
思路:假设根节点的权值为1,假设根节点有3个儿子,那么每个儿子的重量应该是1/3,一次dfs算出所有叶子节点的权重,因为父节点的权重肯定是子节点的lcm,所以算出所有叶子结点的lcm,在dfs时算出以该叶子节点的权值,整棵树的权值,如果lcm大于最小的权值,表明整棵树都需要被删除,lcm小于最小的权值,因为根节点每次只能+lcm,那么离最小权值的一个数是x-x%lcm,让总和减去它就是最后的答案。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e5+7; vector<LL>mp[maxn]; int n; LL gcd(LL x,LL y) { return y==0?x:gcd(y,x%y); } LL lcm(LL x,LL y) { return x/gcd(x,y)*y; } LL a[maxn],val[maxn]; LL sum,lc,minn; bool ok; void dfs(int u,int pre) { if(!ok)return ; if(mp[u].size()==1&&pre!=-1){ minn=min(minn,val[u]*a[u]); lc=lcm(lc,val[u]); if(lc>minn){ ok=false; return ; } } LL cnt=0; for(int i=0;i<mp[u].size();i++){ int v=mp[u][i]; if(v==pre)continue; cnt++; } for(int i=0;i<mp[u].size();i++){ int v=mp[u][i]; if(v==pre)continue; val[v]=val[u]*cnt; dfs(v,u); } } int main() { scanf("%d",&n); sum=0;lc=1,minn=0x3f3f3f3f3f3fLL;ok=true; for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum+=a[i]; for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u); } val[1]=1;val[0]=1; dfs(1,-1); if(!ok){ cout<<sum<<endl; } else{ LL ans=sum-minn+minn%lc; cout<<ans<<endl; } return 0; }
E.Subset Sums
题意:有长度为n的序列,以及m个集合,然后有两种操作,查询操作是输入? X,表示查询集合x中元素的总和,另一种是修改操作,+ a b表示把集合a中的所有元素加上b,每个集合有numi个元素,输入num个元素表示那些元素属于集合i
思路:把集合分为两种,元素个数超过sqrt(n)的集合为重集合,不超过sqrt(n)为轻集合
第i个轻集合更新:直接更新该集合对应的a序列元素,然后更新重集合的总和sum,第j个重集合的sum[j]+=x*(集合i与重集合j交集元素的个数)
第i个重集合更新:累加更新值,加在标记上
第i个轻集合查询:直接累加该集合对应的a序列元素,然后把重集合延迟的更新累加,即累加上(集合i与重集合j交集元素的个数)*add[j]
第i个重集合查询:本身的值累加上重集合延迟的更新,即重集合的总和sum[i]+ (集合i与重集合j交集元素的个数) *add[j]
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e5+7; int n,m,q; LL a[maxn]; int h[maxn]; int cnt[maxn][400]; int res,id[maxn]; LL sum[maxn]; LL add[maxn]; vector<int>mp[maxn],mpp[maxn]; int main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); int num=sqrt(n+0.5),res=0; for(int i=1;i<=m;i++){ int op; scanf("%d",&op); if(op>=num)h[i]=1,id[++res]=i; else h[i]=0; for(int j=0;j<op;j++){ int x; scanf("%d",&x); mp[i].push_back(x); if(h[i])sum[i]+=a[x],mpp[x].push_back(res); } } for(int i=1;i<=m;i++){ for(int j=0;j<mp[i].size();j++){ int u=mp[i][j]; for(int k=0;k<mpp[u].size();k++){ int v=mpp[u][k]; cnt[i][v]++; } } } while(q--){ int k,x; char op[5]; scanf("%s%d",op,&k); if(op[0]=='?'){ LL ans=0; if(h[k]){ ans=sum[k]; for(int i=1;i<=res;i++){ ans+=add[id[i]]*cnt[k][i]; } } else{ for(int i=0;i<mp[k].size();i++)ans+=a[mp[k][i]]; for(int i=1;i<=res;i++)ans+=add[id[i]]*cnt[k][i]; } printf("%lld\n",ans); } else{ scanf("%d",&x); if(h[k])add[k]+=x; else{ for(int i=0;i<mp[k].size();i++)a[mp[k][i]]+=x; for(int i=1;i<=res;i++)sum[id[i]]+=x*cnt[k][i]; } } } return 0; }
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
int n,m,q;
LL a[maxn];
int h[maxn];
int cnt[maxn][400];
int res,id[maxn];
LL sum[maxn];
LL add[maxn];
vector<int>mp[maxn],mpp[maxn];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
int num=sqrt(n+0.5),res=0;
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op>=num)h[i]=1,id[++res]=i;
else h[i]=0;
for(int j=0;j<op;j++){
int x;
scanf("%d",&x);
mp[i].push_back(x);
if(h[i])sum[i]+=a[x],mpp[x].push_back(res);
}
}
for(int i=1;i<=m;i++){
for(int j=0;j<mp[i].size();j++){
int u=mp[i][j];
for(int k=0;k<mpp[u].size();k++){
int v=mpp[u][k];
cnt[i][v]++;
}
}
}
while(q--){
int k,x;
char op[5];
scanf("%s%d",op,&k);
if(op[0]=='?'){
LL ans=0;
if(h[k]){
ans=sum[k];
for(int i=1;i<=res;i++){
ans+=add[id[i]]*cnt[k][i];
}
}
else{
for(int i=0;i<mp[k].size();i++)ans+=a[mp[k][i]];
for(int i=1;i<=res;i++)ans+=add[id[i]]*cnt[k][i];
}
printf("%lld\n",ans);
}
else{
scanf("%d",&x);
if(h[k])add[k]+=x;
else{
for(int i=0;i<mp[k].size();i++)a[mp[k][i]]+=x;
for(int i=1;i<=res;i++)sum[id[i]]+=x*cnt[k][i];
}
}
}
return 0;
}