您的位置:首页 > 其它

APIO2007-2015题解大集合(2008年篇)

2016-04-14 22:43 260 查看
这一系列的题解预计会在未来的一周内陆续出齐。由于作者是现役选手,应该不会弃坑。然而现在由于时间实在太紧张没机会写blog看起来确实要坑了……对不起等后面题解的同学们。。。

珠链交换器

应该算是历年APIO最水的一道题了吧……因为没有强制在线(听说有一种把状态串起来的方法,应该是可以对付强制在线的情况,不过那个时候出题人对于强制在线的意识并不强于是就变水题了……)直接把询问排序然后模拟即可。另外我交题的OJ蛋疼地搞了多个q害得我查了半天错……
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
int n,m,q,c[300005],bead[300005],pos[300005];
struct node{int line,t,id,ans;}ask[300005];
bool Comp(node x,node y)
{return x.t<y.t;
}
bool Comp2(node x,node y)
{return x.id<y.id;
}
void Input()
{scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)//交换器
scanf("%d",&c[i]);
}
void Solve()
{ask[0].t=0;
while(scanf("%d",&q)!=EOF)
{for(int i=1;i<=n;i++)bead[i]=i,pos[i]=i;
for(int i=1;i<=q;i++)
{scanf("%d%d",&ask[i].line,&ask[i].t);
ask[i].id=i;
}
sort(ask+1,ask+q+1,Comp);
for(int i=1;i<=q;i++)
{for(int j=ask[i-1].t+1;j<=ask[i].t;j++)
{swap(bead[c[j]],bead[c[j]+1]);
swap(pos[bead[c[j]]],pos[bead[c[j]+1]]);
}
ask[i].ans=pos[ask[i].line];
}
sort(ask+1,ask+q+1,Comp2);
for(int i=1;i<=q;i++)printf("%d\n",ask[i].ans);
}

}
int main()
{Input();
Solve();
return 0;
}



DNA

首先这题属于计数类DP应该没有异议吧……先把4个字母编号:A=1,C=2,G=3,T=4。
不难写出状态转移方程:f[i,j,k]表示后i位(注意是后i位一会要在前面卡),当前位为j,范式为k的方案数。
f[i][j][k]=∑(f[i+1,l,k或k-1])k或k-1视j与l的关系而定,如果j>l则为k-1,否则为k。对于当前为N的位置要枚举当前位,否则不用枚举,直接就是当前的字母对应的数。
统计出方案数之后,就需要“卡”出答案(这是输出第k大解问题的常见思路)。我们从前到后、从小到大枚举数字(如果不是N就不用枚举了),如果当前r能足够减去f[i,j,k](注意这里的k是在从前往后确定答案的过程中根据前面的情况要变化的),就减去,否则说明当前位就是j,确定当前位,然后接着往后枚举。
最后重要的事情说三遍:要开longlong!要开longlong!要开longlong!CQOI2015不知多少英雄好汉在裸网络流题上不开longlong挂掉了!
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
map<char,LL>mp;
map<LL,char>s;
LL n,K,r,f[50005][5][12]={0};
char ch[50005];
void Input()
{scanf("%lld%lld%lld",&n,&K,&r);
scanf("%s",ch+1);
mp['A']=1,mp['C']=2,mp['G']=3,mp['T']=4;
s[1]='A',s[2]='C',s[3]='G',s[4]='T';
}
void Dp()
{if(ch
=='N')f
[1][1]=f
[2][1]=f
[3][1]=f
[4][1]=1;
else f
[mp[ch
]][1]=1;
for(LL i=n-1;i>=1;i--)
{if(ch[i]=='N')
{for(LL len=1;len<=K;len++)
for(LL j=1;j<=4;j++)
{for(LL k=1;k<=4;k++)
{if(k<j)f[i][j][len]+=f[i+1][k][len-1];
else f[i][j][len]+=f[i+1][k][len];
}
}
}
else
{LL x=mp[ch[i]];
for(LL len=1;len<=K;len++)
{for(LL k=1;k<=4;k++)
{if(k<x)f[i][x][len]+=f[i+1][k][len-1];
else f[i][x][len]+=f[i+1][k][len];
}
}
}
}
for(LL i=1;i<=n;i++)
for(LL j=1;j<=4;j++)
for(LL k=1;k<=K;k++)
f[i][j][k]+=f[i][j][k-1];
}
void Output()
{ch[0]='Q',mp['Q']=0;
LL now=K,temp=r,last;
for(LL i=1;i<=n;i++)
{if(ch[i]!='N')
{if(mp[ch[i]]<mp[ch[i-1]])now--;
}
else
{if(ch[i-1]!='N')
{LL tnow;
for(LL j=1;j<=4;j++)
{if(j<mp[ch[i-1]])tnow=now-1;
else tnow=now;
if(f[i][j][tnow]<temp)temp-=f[i][j][tnow];
else {ch[i]=s[j];now=tnow;break;}
}
}
else
{LL tnow;
for(LL j=1;j<=4;j++)
{if(j<last)tnow=now-1;
else tnow=now;
if(f[i][j][tnow]<temp)temp-=f[i][j][tnow];
else {ch[i]=s[j];now=tnow;break;}
}
}
}
}
printf("%s",ch+1);
}
int main()
{Input();
Dp();
Output();
return 0;
}



免费道路【上古预警】

这题不难,但是比较考验思维。可以用3次kruscal解决。
第一次kruscal:首先考虑把所有水泥路连上。如果此时仍不连通,则需要用鹅卵石路连通,这些鹅卵石路是必须要的鹅卵石路(如果>k直接无解);剩下的鹅卵石路都是不必要的。
第二次kruscal:此时的鹅卵石路不一定恰有K条,可能比K条少,于是考虑尽量连不必要的鹅卵石路,直到凑满K条为止(special judge告诉我们输出任意解均可)
第三次kruscal:把剩下的还需要连的水泥路连上。
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
int cnt=0,cnt_must=0,e=0,u=0,n,m,k,father[20005];
struct node{int a,b,c,tag;}edge[100005],ans[100005];
bool comp(node x,node y)//第一步先把鹅卵石路排在后面
{return x.c>y.c;
}
bool comp2(node x,node y)
{return x.c<y.c;
}
int getfather(int x)
{if(father[x]==x)return x;
father[x]=getfather(father[x]);
return father[x];
}
void input()
{scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].c);
edge[i].tag=0;
}
}
void kruscal1()
{for(int i=1;i<=n;i++)father[i]=i;
for(int i=1;i<=m;i++)
{if(!edge[i].c)continue;
int f1=getfather(edge[i].a),f2=getfather(edge[i].b);
father[f2]=f1;
}
for(int i=1;i<=m;i++)
{if(edge[i].c==1)continue;
int f1=getfather(edge[i].a),f2=getfather(edge[i].b);
if(f1!=f2)
{father[f2]=f1;
edge[i].tag=1;
k--;
}
}
}
void kruscal2()
{int cnt=0;
for(int i=1;i<=n;i++)father[i]=i;
for(int i=1;i<=m;i++)
{if(edge[i].tag==0)continue;
int f1=getfather(edge[i].a),f2=getfather(edge[i].b);
father[f2]=f1;
}
for(int i=1;i<=m;i++)
{if(edge[i].c==1)continue;
int f1=getfather(edge[i].a),f2=getfather(edge[i].b);
if(f1!=f2)
{k--;
father[f2]=f1;
edge[i].tag=1;
if(k==0)break;
}
}
if(k!=0){printf("no solution");exit(0);}
for(int i=1;i<=m;i++)
{if(edge[i].c==0)continue;
int f1=getfather(edge[i].a),f2=getfather(edge[i].b);
if(f1!=f2)
{
edge[i].tag=1;
father[f2]=f1;
}
}
}
int main()
{input();
kruscal1();
kruscal2();
for(int i=1;i<=m;i++)
if(edge[i].tag)printf("%d %d %d\n",edge[i].a,edge[i].b,edge[i].c);
return 0;
}
/*
7 10 6
1 5 0
1 7 0
1 6 1
5 6 1
5 7 1
1 2 0
1 3 0
2 3 1
2 4 1
1 4 0
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: