$$2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest$$
A Nasta Rabbara
B Colored Blankets
只要每组都能用两种以下的颜色合成即可,可以发现答案必然存在,考虑用数量最多的颜色和数量最少的颜色组合,递归处理
略证:颜色最少的数量(le frac{k}{n}),颜色最多的数量(ge frac{k}{n}),每次组合完成之后上述条件不变
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e3+7;
int n,m,k,cnt[MAXN];
pair<int,int> color[MAXN];
vector<int> vec[MAXN];
set<pair<int,int>> S;
int main(){
scanf("%d %d",&n,&k);
m = n / k;
for(int i = 1; i <= n; i++){
scanf("%d",&color[i].first);
if(color[i].first==-1) color[i].first = 1;
vec[color[i].first].emplace_back(i);
}
for(int i = 1; i <= k; i++) if(!vec[i].empty()) S.insert(make_pair(vec[i].size(),i));
puts("Yes");
while(!S.empty()){
auto va = *S.begin();
auto vb = *S.rbegin();
if(va==vb){
int col = vb.second;
while(!vec[col].empty()){
color[vec[col].back()].second = col;
vec[col].pop_back();
}
S.clear();
}
else{
S.erase(va);
S.erase(vb);
int lft = m - va.first%m;
int col = vb.second;
for(int i = 0; i < lft; i++){
color[vec[col].back()].second = va.second;
vec[col].pop_back();
}
col = va.second;
for(int i = 0; i < m - lft; i++){
color[vec[col].back()].second = vb.second;
vec[col].pop_back();
}
va.first-=m-lft;
if(va.first) S.insert(va);
vb.first-=lft;
if(vb.first) S.insert(vb);
}
}
for(int i = 1; i <= n; i++) printf("%d %d
",color[i].first,color[i].second);
return 0;
}
C Component Tree
D Data Center
排序之后先选上最大的直到大于(m),然后再从剩下的里从大到小遍历,用标记为(1)的替换标记为(0)的,直到不能替换位置
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const int MAXN = 2e5+7;
int n;
LL m;
struct STA{
LL val;
int v,idx;
bool operator < (const STA &rhs)const{ return val > rhs.val; }
}sta[MAXN];
int main(){
scanf("%d %I64d",&n,&m);
for(int i = 1; i <= n; i++){
sta[i].idx = i;
scanf("%I64d %d",&sta[i].val,&sta[i].v);
}
sort(sta+1,sta+1+n);
priority_queue<STA,vector<STA>> que;
vector<int> vec;
LL sum = 0;
for(int i = 1; i <= n; i++){
if(sum<m){
sum+=sta[i].val;
if(!sta[i].v) que.push(sta[i]);
else vec.emplace_back(sta[i].idx);
}
else{
if(que.empty()) break;
if(!sta[i].v) continue;
if(sum-que.top().val+sta[i].val>=m){
sum = sum-que.top().val+sta[i].val;
que.pop();
vec.emplace_back(sta[i].idx);
}
}
}
printf("%d %d
",vec.size()+que.size(),vec.size());
for(int i = 0; i < (int)vec.size(); i++) printf("%d ",vec[i]);
while(!que.empty()){
printf("%d ",que.top().idx);
que.pop();
}
return 0;
}
E Election of a Mayor
设当前赢了(w)场,现在考虑合并的时候没有减少赢的场次的有(x)次,减少了1次赢的场次的有(y)次,不可能合并两次都赢的
那么(frac{w-y}{n-x-y}>frac{1}{2} => x-y>n-2·w => x-yge n-2·w+1)
所以尽量合并那些合并之后没有减少赢的场次的即可,dp
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
int n,win,k,f[MAXN];
pair<int,int> sta[MAXN];
vector<pair<int,int>> vec;
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%d %d",&sta[i].first,&sta[i].second);
win += sta[i].first>sta[i].second?1:0;
}
k = n - 2*win + 1;
if(k<=0) return printf("%d
",0),0;
for(int i = 2; i <= n; i++){
if(sta[i].first>sta[i].second){
if(sta[i-1].first>sta[i-1].second) f[i] = f[i-1];
else if(sta[i-1].first==sta[i-1].second) f[i] = max(f[i-1],f[i-2]+1);
else{
if(sta[i].first+sta[i-1].first<=sta[i].second+sta[i-1].second) f[i] = f[i-1];
else f[i] = max(f[i-1],f[i-2]+1);
}
}
else if(sta[i].first==sta[i].second) f[i] = max(f[i-1],f[i-2]+1);
else{
if(sta[i-1].first>sta[i-1].second){
if(sta[i-1].first+sta[i].first>sta[i-1].second+sta[i].second) f[i] = max(f[i-1],f[i-2]+1);
else f[i] = f[i-1];
}
else f[i] = max(f[i-1],f[i-2]+1);
}
if(f[i]==k){
int cur = k, pos = i;
while(cur){
if(f[pos]==cur&&f[pos-1]!=cur){
vec.emplace_back(make_pair(pos-1,pos));
pos-=2;
cur--;
}
else pos--;
}
printf("%d
",k);
for(int i = k-1; i >= 0; i--) printf("%d %d
",vec[i].first,vec[i].second);
return 0;
}
}
puts("-1");
return 0;
}
F Ilya Muromets
其实就是选两部分长为k的区间使和最大,简单DP
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
int n,m,A[MAXN],sum[MAXN],f[MAXN][2];
int main(){
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; i++) scanf("%d",&A[i]);
if(m*2>=n){
printf("%d
",accumulate(A+1,A+n+1,0));
return 0;
}
partial_sum(A+1,A+1+n,sum+1);
for(int i = m; i <= n; i++){
f[i][0] = max(sum[i] - sum[i-m],f[i-1][0]);
f[i][1] = max(f[i-m][0] + sum[i] - sum[i-m],f[i-1][1]);
}
printf("%d
",f[n][1]);
return 0;
}
G FacePalm Accounting
从前往后遍历,尽量选择靠后位置的减小
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
int n,k,A[MAXN],tot;
stack<int> stk;
struct BinaryIndexedTree{
int val[MAXN];
#define lowbit(x) (x)&-(x)
void update(int pos, int x){
while(pos<=n){
val[pos] += x;
pos += lowbit(pos);
}
}
int query(int pos){
int res = 0;
while(pos){
res += val[pos];
pos -= lowbit(pos);
}
return res;
}
}BIT;
int main(){
scanf("%d %d",&n,&k);
for(int i = 1; i <= n; i++){
scanf("%d",&A[i]);
BIT.update(i,A[i]);
}
int minn = *min_element(A+1,A+1+n);
for(int i = 1; i < k; i++) stk.push(i);
for(int i = k; i <= n; i++){
stk.push(i);
int sum = BIT.query(i) - BIT.query(i-k);
if(sum>=0) tot+=sum+1;
while(sum>=0){
if(A[stk.top()]-minn>sum+1){
A[stk.top()] -= sum+1;
BIT.update(stk.top(),-sum-1);
sum = -1;
}
else{
BIT.update(stk.top(),minn-A[stk.top()]);
sum-=A[stk.top()] - minn;
A[stk.top()] = minn;
stk.pop();
}
}
}
printf("%d
",tot);
for(int i = 1; i <= n; i++) printf("%d ",A[i]);
puts("");
return 0;
}
H Minimal Agapov Code
I Sale in GameStore
签到,选上最大的,剩下的0-1背包即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
int n,f[MAXN];
int main(){
scanf("%d",&n);
vector<int> vec(n);
for(int i = 0; i < n; i++) scanf("%d",&vec[i]);
sort(vec.begin(),vec.end());
int mon = vec.back();
vec.pop_back();
for(int i = 0; i < (int)vec.size(); i++)
for(int j = mon; j >= vec[i]; j--)
f[j] = max(f[j],f[j-vec[i]]+1);
printf("%d
",1+f[mon]);
return 0;
}
J Getting Ready for VIPC
K Treeland
考虑离当前节点最远的点必然是叶子节点,叶子节点只有一个点离它距离为1,将叶子节点和最近点连边,然后删除叶子节点,重复操作即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2222;
int T,n,A[MAXN][MAXN],del[MAXN];
int main(){
scanf("%d",&T);
for(int kase = 1; kase <= T; kase++){
scanf("%d",&n);
for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d",&A[i][j]);
for(int i = 1; i <= n; i++) del[i] = 0;
vector<pair<int,int>> vec;
for(int i = n; i >= 3; i--){
int v = A[1][i];
for(int j = 2; j <= n; j++){
if(del[A[v][j]]) continue;
vec.emplace_back(make_pair(v,A[v][j]));
del[v] = 1;
break;
}
}
vec.emplace_back(make_pair(1,A[1][2]));
for(auto p : vec) printf("%d %d
",p.first,p.second);
puts("");
}
return 0;
}
L Useful Roads
以(1)为根建立支配树,遍历每条边,如果是支配树上的返祖边,那必然会经过祖先两次,即不是useful road
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
int n,m,dfn[MAXN],idx[MAXN],num,degree[MAXN],depth[MAXN],par[MAXN][20],root[MAXN],semi[MAXN],msemi[MAXN];
pair<int,int> edge[MAXN];
vector<int> G[MAXN],from[MAXN],rG[MAXN],rfrom[MAXN],newG[MAXN],node;
void init(){
for(int i = 1; i <= n; i++){
G[i].clear();
from[i].clear();
rG[i].clear();
rfrom[i].clear();
newG[i].clear();
memset(par[i],0,sizeof(par[i]));
dfn[i] = idx[i] = degree[i] = 0;
}
num = 0;
node.clear();
}
void tarjan(int u){
dfn[u] = ++num;
idx[num] = u;
for(int v : G[u]){
if(dfn[v]) continue;
tarjan(v);
rG[u].emplace_back(v);
rfrom[v].emplace_back(u);
degree[v]++;
}
}
int findroot(int u){
if(u!=root[u]){
int rt = root[u];
root[u] = findroot(root[u]);
msemi[u] = min(msemi[u],msemi[rt]);
}
return root[u];
}
void calsemi(){
for(int i = 1; i <= n; i++){
root[i] = i;
msemi[i] = dfn[i];
}
for(int i = n; i >= 2; i--){
if(!idx[i]) continue;
int u = idx[i],tar = n;
for(int v : from[u]){
if(!dfn[v]) continue;
if(dfn[v]<dfn[u]) tar = min(tar,dfn[v]);
else{
findroot(v);
tar = min(tar,msemi[v]);
}
}
semi[u] = idx[tar];
msemi[u] = tar;
root[u] = rfrom[u][0];
rG[semi[u]].emplace_back(u);
rfrom[u].emplace_back(semi[u]);
degree[u]++;
}
}
void toposort(){
queue<int> que;
que.push(1);
while(!que.empty()){
int u = que.front();
que.pop();
for(int v : rG[u]){
degree[v]--;
if(!degree[v]){
node.emplace_back(v);
que.push(v);
}
}
}
}
int LCA(int u, int v){
if(depth[u]<depth[v]) swap(u,v);
for(int i = 0; i < 20; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
if(u==v) return u;
for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
u = par[u][i];
v = par[v][i];
}
return par[u][0];
}
void buildtree(){
for(int u : node){
if(rfrom[u].empty()) continue;
par[u][0] = rfrom[u][0];
for(int v : rfrom[u]) par[u][0] = LCA(par[u][0],v);
depth[u] = depth[par[u][0]] + 1;
newG[par[u][0]].emplace_back(u);
for(int i = 1; par[u][i-1]; i++) par[u][i] = par[par[u][i-1]][i-1];
}
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
init();
for(int i = 1; i <= m; i++){
scanf("%d %d",&edge[i].first,&edge[i].second);
from[edge[i].second].emplace_back(edge[i].first);
G[edge[i].first].emplace_back(edge[i].second);
}
tarjan(1);
calsemi();
toposort();
buildtree();
vector<int> vec;
for(int i = 1; i <= m; i++){
if(!dfn[edge[i].first]||!dfn[edge[i].second]) continue;
int lca = LCA(edge[i].first,edge[i].second);
if(lca!=edge[i].second) vec.emplace_back(i);
}
printf("%d
",vec.size());
for(int x : vec) printf("%d ",x);
puts("");
}
return 0;
}
M Variable Shadowing
用栈模拟即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
int n,tot;
char prog[MAXN][MAXN];
stack<int> bracket;
stack<pair<int,pair<int,int>>> alp[MAXN];
vector<pair<pair<pair<int,int>,pair<int,int>>,char>> res;
int main(){
____();
cin >> n;
cin.get();
for(int i = 1; i <= n; i++) cin.getline(prog[i]+1,MAXN);
bracket.push(0);
for(int i = 1; i <= n; i++){
int len = strlen(prog[i]+1);
for(int p = 1; p <= len; p++){
if(prog[i][p]==' ') continue;
if(prog[i][p]=='{') bracket.push(++tot);
else if(prog[i][p]=='}'){
for(int k = 0; k < 26; k++) while(!alp[k].empty()&&alp[k].top().first==bracket.top()) alp[k].pop();
bracket.pop();
}
else{
int ch = prog[i][p] - 'a';
if(!alp[ch].empty()) res.emplace_back(make_pair(make_pair(make_pair(i,p),alp[ch].top().second),prog[i][p]));
alp[ch].push(make_pair(bracket.top(),make_pair(i,p)));
}
}
}
for(auto p : res){
cout << p.first.first.first << ':' << p.first.first.second << ": warning: shadowed declaration of " << p.second
<< ", the shadowed position is " << p.first.second.first << ':' << p.first.second.second << endl;
}
return 0;
}