训练计划:做 Codeforces Round (Div. 3)、Codeforces Round (Div. 3) 和 Educational Codeforces Round 通过人数少于 1000 人的题目。
Codeforces Round #490 (Div. 3)
D. Equalize the Remainders
给定两个整数 和 个整数 组成的数列 ,每次可以将数列 中的任意一个整数加 ,至少需要多少次操作才能使得在所有 中, 都出现 次。
数据保证 且 。
对于每个余数,统计在数列中的下标,将余数数列复制一份到末尾,每次余数个数大于 的部分加入队列,对于小于 的部分尝试用队列中的数补齐即可。
#include <cstdio>
#include <queue>
typedef long long int ll;
const int maxn=(int)2e5+5;
int arr[maxn],add[maxn];
std::queue<int> remainders[2*maxn];
struct element {int id,val;};
int main() {
int n,m;scanf("%d%d",&n,&m);
int cnt=n/m;
for(int i=0;i<n;++i) {
scanf("%d",&arr[i]);
remainders[arr[i]%m].push(i);
remainders[arr[i]%m+m].push(i);
}
std::queue<element> q;ll ans=0;
for(int i=0;i<2*m;++i) {
while(remainders[i].size()>cnt) {
q.push((element){remainders[i].front(),i});
remainders[i].pop();
if(i<m) remainders[i+m].pop();
else remainders[i-m].pop();
}
while(remainders[i].size()<cnt&&q.size()) {
element ele=q.front();q.pop();
ans+=add[ele.id]=i-ele.val;
remainders[i].push(ele.id);
if(i<m) remainders[i+m].push(ele.id);
else remainders[i-m].push(ele.id);
}
}
printf("%I64d\n%d",ans,arr[0]+add[0]);
for(int i=1;i<n;++i) printf(" %d",arr[i]+add[i]);
printf("\n");
return 0;
}
E. Reachability from the Capital
给出 个点, 条边的有向图,求要使起点 能够到达其它所有的节点,至少需要增加几条边。
,不存在重边。
首先将所有与起点连通的节点标记,对于其它节点扫描其能到达的节点个数,按可达节点个数从大到小依次标记该节点和与它可达的节点,已经标号的节点跳过。
注:存在时间复杂度为
的解法。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
const int maxn=5005;
std::vector<int> g[maxn];
int vis[maxn];
void dfs(int x) {
vis[x]=true;
for(int i=0,end=g[x].size();i<end;++i) {
int v=g[x][i];
if(!vis[v]) dfs(v);
}
}
struct element {int id,cnt;};
inline int cmp(const element &x,const element &y) {return x.cnt>y.cnt;}
int vis2[maxn],cnt=0;
void dfs2(int x) {
vis2[x]=true;++cnt;
for(int i=0,end=g[x].size();i<end;++i) {
int v=g[x][i];
if(!vis2[v]) dfs2(v);
}
}
int main() {
int n,m,s;
scanf("%d%d%d",&n,&m,&s);
int u,v;
while(m--) {
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
dfs(s);
std::vector<element> vec;
for(int i=1;i<=n;++i) {
if(!vis[i]) {
memset(vis2,0,sizeof(vis2));cnt=0;
dfs2(i);
vec.push_back((element){i,cnt});
}
}
std::sort(vec.begin(),vec.end(),cmp);
int ans=0;
for(int i=0,end=vec.size();i<end;++i) {
if(!vis[vec[i].id]) {
++ans;
dfs(vec[i].id);
}
}
printf("%d\n",ans);
return 0;
}
F. Cards and Joy
给你 个卡片,每张卡片上都写有数字,将卡片分给 个人,使得每个人手中有 张卡片。每个人都有自己最喜欢的卡片数字,获得 张写有自己最喜欢数字的卡片可以给总答案增加 的开心值,求最大的总开心值。
, ,保证 。
定义 为 个人共获得自己最喜欢的 张卡片的最大开心值。对于每种卡片上的数字,统计最喜欢该数字的人数和写有该卡片的个数,统计即可。
#include <cstdio>
#include <algorithm>
typedef long long int ll;
int c[100005]/*写有i的卡片个数*/,f[100005]/*f[i]:喜欢i的人的个数*/,h[15]/*h[i]:拥有i张自己喜欢的卡片的开心值*/;ll dp[505][5005]/*dp[i][j]:i个人喜欢的有j张卡片最大开心值*/;
int main() {
int n,k;
scanf("%d%d",&n,&k);
int x;
for(int i=0;i<n*k;++i) {
scanf("%d",&x);
++c[x];
}
for(int i=0;i<n;++i) {
scanf("%d",&x);
++f[x];
}
for(int i=1;i<=k;++i) scanf("%d",&h[i]);
for(int i=1;i<=n;++i) {//i个人
for(int j=1;j<=n*k;++j) {//j张卡片
for(int kk=0;kk<=k;++kk) {//第i个人的卡片数
if(j>=kk) dp[i][j]=std::max(dp[i][j],dp[i-1][j-kk]+h[kk]);
}
}
}
ll ans=0;
for(int i=1;i<=100000;++i) ans+=dp[f[i]][c[i]];
printf("%I64d\n",ans);
return 0;
}
待更。。。