您的位置:首页 > 其它

codeforces---748

2017-03-02 10:09 225 查看
D题

题意:给出k个长度为n的字符串,每个串有一个价值vi,现在请用这k个串(不必全用完)构成一个长的回文串,使这个串价值最大。

做法:先注意到一点:他们的长度是相等的,所以其实说是回文但实际并不需要什么后缀数组的,因为一个串在回文的另一端必定只对应另一个完整的串。贪心,先处理出来每个串是否回文,若否,它的对应串是谁(这里我们需要用map来编号),并把这个串的所有值存到它的优先队列里。

先对于所有不是回文的进行一番贪心:若它和它的对应串的最大值之和>0,那么就把这个值加到ans里,代表我选了它们作为总串的一部分。然后pop掉并继续这个操作直到两者的最大值<=0;

.对于是回文的,操作与上者差不多,改成了自己和自己贪心,但注意,它们也可以选一个作为中心串。所以维护一个值mx表示选一个串当作中心串所能获得的最大优化利益(初始化肯定为0).在和自己贪心的过程中,若优先队列里只剩一个值,那么mx=max(mx,q.top())。若贪心加的两个值中的较小值<0,那么也要与这个值的相反数取一下最大值(即把较大值作为中心串时获得的优化利益),还要注意若较大值次大值<=0时需要注意,若x1>0,优化利益也需要和它做一个max,再break。

最后输出ans+mx即可。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int N=100050;
string s,rank
;
vector<int> a,b;
map<string,int> ma;
int cnt,n,k,v;
struct st
{
priority_queue<int,vector<int>,less<int> > q;
int dui;
}gh
;
int ans=0,bu=0;
int main()
{
scanf("%d%d",&k,&n);
for(int i=1;i<=k;i++)
{
cin>>s;
cin>>v;
if(!ma[s])
ma[s]=++cnt,rank[cnt]=s;
gh[ma[s]].q.push(v);
}
for(int i=1;i<=cnt;i++)
{
string now=rank[i],rev;
for(int j=n-1;j>=0;j--)
rev+=now[j];
int to=ma[rev];
gh[i].dui=to;
if(to==i)
a.push_back(i);
else if(to)
b.push_back(i);
}
for(int i=0;i<b.size();i++)
{
int to=gh[b[i]].dui;
if(gh[b[i]].q.empty()||gh[to].q.empty())
continue;
while(gh[b[i]].q.top()+gh[to].q.top()>0)
{
ans+=gh[b[i]].q.top()+gh[to].q.top();
gh[b[i]].q.pop(),gh[to].q.pop();
if(gh[b[i]].q.empty()||gh[to].q.empty())
break;
}
}
for(int i=0;i<a.size();i++)
{
int now=a[i];
if(gh[now].q.size()==1)
{
bu=max(bu,gh[now].q.top());
continue;
}
int x1=gh[now].q.top();gh[now].q.pop();
int x2=gh[now].q.top();gh[now].q.pop();
while(x1+x2>0)
{
ans+=x1+x2;
if(x2<0)
bu=max(bu,-x2);
if(gh[now].q.empty())
break;
if(gh[now].q.size()==1)
{
bu=max(bu,gh[now].q.top());
break;
}
x1=gh[now].q.top(),gh[now].q.pop(),x2=gh[now].q.top(),gh[now].q.pop();
}
if(x1+x2<=0)
bu=max(bu,x1);
}
cout<<ans+bu<<endl;
}
E题

题意:一个圣诞老人有一堆橘子,每个有vi瓣,现在给k个熊孩子分橘子。每次圣诞老人因为手残只能把一个橘子或一个整块橘子瓣们分成vi/2和vi-vi/2两半,而熊孩子们也只要整块的橘子(即一个完整的橘子或一块切出来的橘子瓣们),最终圣诞老人获得的快乐值为所有人中获得橘子瓣数最少的那个,问圣诞老人所能获得的最大快乐值是多少。

做法:最大的最小值!二分!

然而。。其实并不需要二分。。。。

cnt[i]表示瓣数为i的橘子有多少个,tot表示现在最小的是i时能切出多少块。

那么每到一个瓣数时,tot+=cnt[i],tot-=cnt[2*i],tot-=cnt[2*i-1]表示加上这个块数,但它是由2*i和2*i-1转移过来的,所以要把它们的个数减去.

有人(开始的在下。。)会不服:那为什么不减cnt[2*i+1]?1.若两个都减,那么一个瓣数的值会被所切成的两部分各减一次,那么就减多啦!2.如果只减cnt[2*i+1]而非cnt[2*i],以9为例,它会在i=4时被减,那么先前在i=5时tot就大了。

当tot>=k时,输出i.

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<queue>
using namespace std;
queue<int> q;
int n,mx,a[1000050],k;
long long cnt[10000050],sum;
long long tot;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),sum+=a[i],mx=max(mx,a[i]),cnt[a[i]]++;
if(sum<k)
{
printf("-1");
return 0;
}
for(int i=mx;i>=1;i--)
{
tot+=cnt[i];
if(1<i*2&&i*2<=mx)
tot-=cnt[i*2];
if(1<i*2-1&&i*2-1<=mx)
tot-=cnt[i*2-1];
// if(1<i*2+1&&i*2+1<=mx)
// tot-=cnt[i*2+1];
if(tot>=k)
{
printf("%d\n",i);
return 0;
}
cnt[i/2]+=cnt[i],cnt[i-i/2]+=cnt[i];
}
}
F题(第一道凭自己能力做出来的F题,感动!)

题意:给出一幅地图,n个城市成树状相连,现在给出2*k个队伍,他们来自不同的城市,现在比赛期间他们要组成k对比赛对手,对于每对比赛对手,他们在比赛期间所住的城市一定是他们俩各自城市最短路上的一个城市(可以是这两个端点城市)。现在委员会想让所有队伍所住城市的总数最小,问最小是多少,并且他们都在那,还有此时每对对手由谁组成,以及他们住哪一个。

做法:结论:只需要一个城市。理由:只要一个城市T它的儿子节点所含队伍数不超过k个,那么这个城市便可以作为所有队伍所住的城市,因为可以给任意一个队伍找一个不在同一棵T的儿子子树的队伍与它匹配,而此时这两支队伍的最短路一定经过T(因为T是他们的LCA)。

先用treedp找出来选哪个城市,然后用一遍dfs处理每个儿子子树所含的队伍原城市,存到一个队列里,再用一个优先队列进行分配即可,注意特判当T为队伍原城市时那它去跟剩下优先队列没处理的那个城市匹配。

#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int N=200050;
int head
,to[2*N],next[2*N],cnt,mx
,size
;
int ans1;
int n,k;
struct state
{
int siz,dui;
friend bool operator < ( state a,state b)
{
return a.siz<b.siz;
}
};
priority_queue<state> q;
void add(int u,int v)
{
to[++cnt]=v;
next[cnt]=head[u];
head[u]=cnt;
}
int u,v;
queue<int> tu
;
int x
,h
;
void dfs(int now,int last)
{
mx[now]=0;
for(int i=head[now];i!=-1;i=next[i])
{
if(to[i]==last)
continue;
dfs(to[i],now);
size[now]+=size[to[i]];
mx[now]=max(mx[now],size[to[i]]);
}
if(h[now]==1)
size[now]++;
mx[now]=max(mx[now],2*k-size[now]);
if(mx[now]<=k&&(!ans1))
ans1=now;
}
int ax
;
void dfs2(int now,int flag,int last)
{
if(h[now])
tu[flag].push(now);
for(int i=head[now];i!=-1;i=next[i])
{
if(to[i]!=last)
dfs2(to[i],flag,now);
}
}
struct daan
{
int f,t;
}ans2
;
int num=0;
void solve()
{
int cnt1=0;
for(int i=head[ans1];i!=-1;i=next[i])
{
dfs2(to[i],++cnt1,ans1);
if(tu[cnt1].size())
q.push((state){tu[cnt1].size(),cnt1});
}
state maxx=q.top();
q.pop();
while(!q.empty())
{
state now=q.top();
q.pop();
if(now.siz>maxx.siz)
{
q.push(maxx);
maxx=now;
continue;
}
ans2[++num].f=tu[now.dui].front();
tu[now.dui].pop();
ans2[num].t=tu[maxx.dui].front();
tu[maxx.dui].pop();
maxx.siz--;
now.siz--;
if(now.siz)
q.push(now);
if(q.empty()&&maxx.siz)
{
maxx.siz--;
ans2[++num].f=tu[maxx.dui].front();
tu[maxx.dui].pop();
ans2[num].t=ans1;
break;
}
if(!maxx.siz)
{
if(q.empty())
break;
else
maxx=q.top(),q.pop();
}
}
if(maxx.siz)
{
maxx.siz--;
ans2[++num].f=tu[maxx.dui].front();
ans2[num].t=ans1;
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>k;
for(int i=1;i<n;i++)
scanf("%d%d",&u,&v),add(u,v),add(v,u);
for(int i=1;i<=2*k;i++)
scanf("%d",&x[i]),h[x[i]]++;
dfs(1,0);
cout<<1<<endl;
cout<<ans1<<endl;
solve();
for(int i=1;i<=num;i++)
cout<<ans2[i].f<<" "<<ans2[i].t<<" "<<ans1<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: