首页 > 代码库 > Codeforces Round #381 (Div. 2)
Codeforces Round #381 (Div. 2)
今天模拟了一套,被c题卡死了WCCCCCCCC。
A - Alyona and copybooks
题目大意:mike有 n 本书,他需要买到4的倍数本书,买一本书需要a元,二本b元,三本c元,
问你最少需要多少钱。
思路:水题,一共只有4种情况n对四 余 1,2,3,4。 枚举一下就好了。
#include<bits/stdc++.h> #define ll long long using namespace std; ll n,a,b,c; int main() { cin>>n>>a>>b>>c; ll ans=1e18; if(n%4==0) { ans=0; } else if(n%4==3) { ans=min(ans,a); ans=min(ans,3*c); ans=min(ans,b+c); } else if(n%4==2) { ans=min(ans,2*a); ans=min(ans,b); ans=min(ans,2*c); } else if(n%4==1) { ans=min(ans,c); ans=min(ans,3*a); ans=min(ans,a+b); } cout<<ans<<endl; return 0; }
B - Alyona and flowers
题目大意:有n个数,给你m个区间,让你选择若干个区间覆盖区间中的点,这些数的价值为
各个数字与其覆盖次数乘积的和,问你价值最大是多少。
思路:判断一个区间要不要覆盖就是,判断覆盖后整体的值是变大还是变小,这样思路就很
明确了。
#include<bits/stdc++.h> using namespace std; int w[105],cnt[105],sum[105]; int n,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum[i]=sum[i-1]+w[i]; while(m--) { int l,r; scanf("%d%d",&l,&r); if(sum[r]-sum[l-1]>0) for(int i=l;i<=r;i++) cnt[i]++; } int ans=0; for(int i=1;i<=n;i++) ans+=cnt[i]*w[i]; printf("%d\n",ans); return 0; }
C - Alyona and mex
题目大意:有n个数,定义mex( l , r )运算为在l -> r 中未出现过的最小自然数,给你 m 个区间
让你构造出这n个数,使mex值最小区间的值最大。
妈的,疯狂宕机,我是猪脑子吧???!!!!
我一直在考虑如何使每个区间都最优,就这样想了一个半小时,得出一个结论,这题我不会写,
我他妈的******************************。
思路:其实我们只需要将每个区间都保证其mex值大于等于最小的mex值,其中区间mex最小
的最大值,肯定是其区间的长度,设这个值为x。所以我们只要保证所有区间mex大于等于x
就行了,我们只需要从第一个数开始给他们赋值,0,1,……,x-1,这样一个循环赋值就好了。
#include<bits/stdc++.h> using namespace std; int n,m; int main() { cin>>n>>m; int mn=n; while(m--) { int l,r; scanf("%d%d",&l,&r); mn=min(mn,r-l+1); } int now=0; cout<<mn<<endl; for(int i=1;i<=n;i++) { cout<<now++<<" "; if(now==mn) now=0; } return 0; }
D - Alyona and a tree
题目大意:给你一棵以 1 为根的树每棵树都有一个权值a[ i ],每条边也有一个权值e[ i ],一个
节点u 管理 一个节点 v的条件是,1. v 是 u 的子节点,2. 从 u 到 v 的所有边的权值和小于
v 的权值和。 问你每个节点管理多少个节点。
我感觉这题是个好题,我学到好多啊。
思路:我们设 d( u ) 表示 1 到 u 边的权值和,那么 u 管理 v 可以表示成 d( v ) - d( u ) <= a[ v ]
我们可以移项得到,d( v ) - a[ v ] <= d( u ),这样我们能保存路径,用lower_bound找到第一个
小于d( v ) - a[ v ]的 d( u ),那样问题就变成了怎么更新,我们可以利用类似于前缀和的思想,
用ans[ i ]来保存答案,是找到的那个 u 的ans[ u ]减去一,这样我们在回溯的时候,他的父节点
及他的祖宗都减去一了,然后我们每次dfs下一个节点回来的时候,设当前节点为a,刚从节点
b回溯回来,那么我们就 ans[ a ]+=ans[ b ]+1;这样我们通过继续回溯,就能将 a 的父节点及
祖宗全部都加上一,可以这么想,如果没有之前的lower_bound找节点减去1,之后后边的
加一,那么ans[ i ]的值就是,i 下面所有的子节点。
#include<bits/stdc++.h> #define ll long long #define pii pair<ll,int> #define pb push_back #define mk make_pair #define fi first #define se second using namespace std; const int N=2*1e5+5; vector<pii> e[N],r;//r 保存当前的路径。 int n; ll a[N],ans[N],d[N]; void dfs(int u) { r.pb(mk(d[u],u)); int t=lower_bound(r.begin(),r.end(),mk(d[u]-a[u],-1))-r.begin()-1; if(t>=0) ans[r[t].se]--;//找到的点的ans-1,通过回溯,其上面的节点也都-1了。 for(int i=0;i<e[u].size();i++) { pii v=e[u][i]; d[v.se]=d[u]+v.fi; dfs(v.se); ans[u]+=ans[v.se]+1;//使u这个节点的ans加上v这个点的ans,回溯使u上面的节点都加上了v } r.pop_back(); } int main() { cin>>n; for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); for(int i=2;i<=n;i++) { int p; ll w; scanf("%d%I64d",&p,&w); e[p].pb(mk(w,i)); } dfs(1); for(int i=1;i<=n;i++) printf("%I64d%c",ans[i],i==n ? ‘\n‘:‘ ‘); return 0; }
Codeforces Round #381 (Div. 2)