记又一次unhappy考试(10.6)

来源:互联网 发布:投标书编制软件 编辑:程序博客网 时间:2024/06/14 10:34

爆零自动机
unhappy
还好有人陪我爆零。
据说题目很简单,也据说代码很短,最后知道真相的我眼泪掉下来。。。。

题解时间

T1题解
T1自爆了,还没写。

好了把T1膜完了,现在补上去。
T1的思路真是“简单清新”。图是一个带环的树,而且保证只有一个环。我们只要对于一条链上的所有小的子树依次DP,然后判断起点和终点的位置,如果起点和终点在一棵树上,那么只要子树上瞎搞就好了;如果不在一棵树上,就得考虑多棵树的影响。在统计距离的时候,采用相对距离,如P1和P2相距L1,P1和P3相距L2,可知P2和P3相距L2-L1,于是计算的时候只需要简单粗暴地给P2到P3的距离暴力减掉L2-L1,这样前面记录的距离就都不需要进行改动了,真神奇。

代码如下:

/***********************orz orz orz nbdhhzh ypa***********************/#pragma GCC optimize ("O2")#include <bits/stdc++.h>#define C(a) memset(a,0,sizeof(a))#define M 400010using namespace std;int n,m,i,j,l,lj,T,cas,cnt,S,ans,tot;int v[M],a[M],b[M],c[M],fa[M],d[M],mx[M],f[M],p[M],q[M],he[M],to[M],ne[M];inline void add(int x,int y){to[++tot]=y;ne[tot]=he[x];he[x]=tot;}inline void up(int x,int y,int k){    if(x>y) swap(x,y);    if(k>ans||k==ans&&x<S||k==ans&&x==S&&y<T) S=x,T=y,ans=k;}inline void dfs(int x){    v[x]=1;int i,y;    for(i=he[x];y=to[i],i;i=ne[i]){        if(!f[i]&&!cnt) if(!v[y])            f[i]=f[i^1]=1,fa[y]=i,dfs(y);        else{            for(int j=x;j!=y;j=to[fa[j]^1])                f[fa[j]]=f[fa[j]^1]=2,c[++cnt]=j;            c[++cnt]=y;f[i]=f[i^1]=2;return;        }    }}inline void dfs1(int x){    int i,y,mx1=x,mx2=x;    for(d[x]=d[fa[x]]+1,mx[x]=x,i=he[x];y=to[i],i;i=ne[i])        if(!f[i]){            f[i]=f[i^1]=1;fa[y]=x;dfs1(y);            if(d[mx[y]]>d[mx[x]]||d[mx[y]]==d[mx[x]]&&mx[y]<mx[x]) mx[x]=mx[y];            if(d[mx[y]]>d[mx2]||d[mx[y]]==d[mx2]&&mx[y]<mx2){                mx2=mx[y]; if(d[mx2]>d[mx1]||d[mx2]==d[mx1]&&mx2<mx1) swap(mx1,mx2);            }        }up(mx1,mx2,d[mx1]+d[mx2]+cnt-2*d[x]);}int main(){    for(scanf("%d",&lj);tot=1,S=T=ans=cnt=0,lj--;){        C(he),C(ne),C(to),C(v),C(d),C(mx),C(fa),C(f),C(q),C(p);        for(C(a),C(b),C(c),scanf("%d",&n),i=1;i<=n;i++)            scanf("%d%d",&a[i],&b[i]),add(a[i],b[i]),add(b[i],a[i]);        for(dfs(1),i=2;i<=tot;i++) if(f[i]!=2) f[i]=0;        for(i=1;i<=n;i++) v[i]=0,fa[i]=0;        for(i=1;i<=cnt;i++) dfs1(c[i]);        for(i=1;i<=cnt;i++) c[i+cnt]=c[i];        for(i=1;i<=cnt*2;i++) p[i]=d[mx[c[i]]]+i;        for(int w=0,t=i=1;i<=cnt*2;q[++w]=i,i++){            if(q[t]==i-cnt) t++;            if(t<=w) up(mx[c[i]],mx[c[q[t]]],p[q[t]]+d[mx[c[i]]]-i+cnt);            while(t<=w&&((p[i]>p[q[w]])||(p[i]==p[q[w]])&&(c[i]<c[q[w]]))) w--;        }printf("Case #%d: %d %d %d\n",++cas,n*2-ans,S,T);    }return 0;}

T2题解
简直就是思考题,思想难度++,实现难度–。惊讶地发现,只要选择了大于等于6个点,必定有符合条件的三个点(显然法)。所以只要求出所有可以选的情况,然后再暴力枚举最多5个点不可能的情况减掉,然后就过了。。。。过了。。。。
灰常暴力。。。

代码如下:

/*******************orz orz nbdhhzh ypa*******************/#pragma GCC optimize ("O2")#include <bits/stdc++.h>#define P 1000000007using namespace std;int n,m,T,cas,ans,a,b,c,d,e;int f[60][60];bool ok(int x,int y,int z){return f[x][y]==f[y][z]&&f[x][y]==f[x][z];}int main(){    for(scanf("%d",&T),cas=1;cas<=T;cas++){        memset(f,0,sizeof(f));scanf("%d%d",&n,&m);        ans=((1LL<<n)-1-n-n*(n-1)/2)%P;        for(e=1;e<=m;e++) scanf("%d%d",&a,&b),f[a][b]=f[b][a]=1;        for(a=1;a<=n;a++) for(b=a+1;b<=n;b++) for(c=b+1;c<=n;c++){            for(ans-=!ok(a,b,c),d=c+1;d<=n;d++)                for(ans-=!(ok(a,b,c)|ok(a,b,d)|ok(a,c,d)|ok(b,c,d)),e=d+1;e<=n;e++)                    ans-=!(ok(a,b,c)|ok(a,b,d)|ok(a,b,e)|ok(a,c,d)|ok(a,c,e)|                        ok(a,d,e)|ok(b,c,d)|ok(b,c,e)|ok(b,d,e)|ok(c,d,e));            ans+=(ans<0)?P:0;        }printf("Case #%d: %d\n",cas,ans);    }return 0;}

T3题解
T3有个灰常神奇的思路。非常显然的是,如果你把一个增加
的字母或是替换的字母或是交换过来的字母给删了,建议你去看一下医生。然后黈黈黈提出了一个根本不理解为什么的方案,举个栗子:
agccct
tcca
一串如果要变到二串,只要把一串
’a‘和’t‘之间的东西全删了,然后交换’a‘和’t‘然后再把’c‘、’c‘给加进去就好了,于是就神奇了。。。。
对于一串的某个字母,只要在二串里相同位置向前寻找第一个相同的字母,然后使用以上的操作即可。

代码如下:

/******************orz orz nbdhhzh ypa******************/#pragma GCC optimize ("O2")#include <bits/stdc++.h>using namespace std;int t1,t2,t3,t4,n,m,i,j,l1,l2,t,tt1,tt2;int f[4010][4010],g[2][4010][30];char s1[4010],s2[4010];int main(){    scanf("%d%d%d%d%s%s",&t1,&t2,&t3,&t4,s1+1,s2+1);    for(l1=strlen(s1+1),l2=strlen(s2+1),i=1;i<=l1;i++){        for(f[i][0]=i*t2,j=0;j<26;j++) g[0][i][j]=g[0][i-1][j];        if(i>1) g[0][i][s1[i-1]-97]=i-1;    }for(i=1;i<=l2;i++){        for(f[0][i]=i*t1,j=0;j<26;j++) g[1][i][j]=g[1][i-1][j];        if(i>1) g[1][i][s2[i-1]-97]=i-1;    }for(i=1;i<=l1;i++) for(j=1;j<=l2;j++){        f[i][j]=min(f[i-1][j]+t2,f[i][j-1]+t1);        t=(s1[i]!=s2[j])*t3+f[i-1][j-1];        if(f[i][j]>t) f[i][j]=t;        if((tt1=g[0][i][s2[j]-97])&&(tt2=g[1][j][s1[i]-97]))            t=f[tt1-1][tt2-1]+(i-tt1-1)*t2+(j-tt2-1)*t1+t4,            f[i][j]=(f[i][j]>t)?t:f[i][j];    }printf("%d\n",f[l1][l2]);return 0;}

整天氧气开开我已经没有希望了

0 0