以下吐槽时间请无视:woc你TM再给我两分钟!!再给我两分钟!!我就可以A了T4了。。。赛后交oj真的是1A啊。。。1A啊!!!!!那score就上4500!!!就rank2了!!!那就上div1了呀(雾)。。。。woc上帝再给我两分钟吧T_T~~T_T~~
T1:LCP Array
题意:已知一个字符串相邻两个后缀(指下标相邻)的最长共同前缀,求可行的字符串个数。
我们发现,如果a[i]>0,那么显然有s[i]=s[i+1]。并且可以推理得必有a[i]=a[i+1]+1或者a[i]=0,这样就可以判断无解输出0了。另一方面,我们发现s[1]有26种取法,另外如果s[i]!=s[i+1]那么s[i+1]有25种取法否则有1种取法。那么用乘法原理累乘起来就好了。
时间复杂度O(N)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long #define mod 1000000007 using namespace std; int n,a[1000005]; int solve(){ int i; ll ans=26; for (i=1; i<n; i++) scanf("%d",&a[i]); a[n]=0; for (i=n-1; i; i--){ if (!a[i]) ans=ans*25%1000000007; else if (a[i]!=a[i+1]+1) return 0; } return ans; } int main(){ int cas; scanf("%d",&cas); while (cas--){ scanf("%d",&n); printf("%d\n",solve()); } return 0; }
T2:Shortest Path
题意:一开始所有点都在一条链上,满足dist(i,i+1)=1,现在加入三条边(i,j)且dist(i,j)=1,求s-t的最短路。多组询问。
显然s-t一定是从s出发,走过若干个新加的边,最后到达t。那么可以用dfs枚举新加入的三条边(i,j)加入的顺序,加入时需要枚举方向,然后再求最短路就行了(语死早具体看代码)。
时间复杂度O(MN!2^N),其中N=3。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #define mod 1000000007 #define ll long long using namespace std; int n,m,ans,x,y,a[10][2]; bool bo[10]; void dfs(int k,int now,int d){ if (d+abs(now-y)<ans) ans=d+abs(now-y); if (k>3) return; int i; for (i=1; i<=3; i++) if (bo[i]){ bo[i]=0; dfs(k+1,a[i][1],d+abs(now-a[i][0])+1); dfs(k+1,a[i][0],d+abs(now-a[i][1])+1); bo[i]=1; } } int main(){ int cas; scanf("%d",&cas); while (cas--){ scanf("%d%d",&n,&m); int i; for (i=1; i<=3; i++) scanf("%d%d",&a[i][0],&a[i][1]); memset(bo,1,sizeof(bo)); ll sum=0; for (i=1; i<=m; i++){ scanf("%d%d",&x,&y); ans=abs(y-x); dfs(1,x,0); sum=(sum+(ll)ans*i)%mod; } printf("%I64d\n",sum); } return 0; }
T3:Transform
题意:有两种变换:1.将x异或某个2的幂;2.将x异或某个给定的ai;多次询问从S变换到T的最小步数。
相当于求0-S^T的最短步数。预处理后O(1)判断。
时间复杂度O(A(logA+N)+M)。其中A表示>=ai的最小的2的幂,本题为2^17。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long #define mod 1000000007 using namespace std; int n,m,a[25],h[300005],d[300005],bin[25]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } int main(){ int cas=read(),i; bin[0]=1; for (i=1; i<=17; i++) bin[i]=bin[i-1]<<1; while (cas--){ n=read(); m=read(); memset(d,-1,sizeof(d)); d[0]=0; for (i=1; i<=n; i++) scanf("%d",&a[i]); int head=0,tail=1; h[1]=0; while (head<tail){ int x=h[++head]; for (i=1; i<=n; i++){ int y=x^a[i]; if (d[y]==-1){ d[y]=d[x]+1; h[++tail]=y; } } for (i=0; i<17; i++){ int y=x^bin[i]; if (d[y]==-1){ d[y]=d[x]+1; h[++tail]=y; } } } ll ans=0; for (i=1; i<=m; i++){ int x=read(),y=read(); ans=(ans+(ll)i*d[x^y])%mod; } printf("%I64d\n",ans); } return 0; }
T4:Toposort
题意:给定一个N点M边的DAG,可以删去恰好k条边,求字典序最小的可行拓扑序列。
显然,如果现在x是所有删去<=k条边可以使得入度=0的最小的点(即入度<=k的点),那么一定要先把x给弄出来(就是把连向x的边删掉)。那么我们用一个堆,维护所有入度<=k的点,然后每次取出最小的点作为拓扑序列的下一个值,然后把这条边的出边删掉,同时k减去这个点的入度。注意k是会减小的,因此每次需要把堆中入度>k的边删去,具体不需要每次更新,只需要取最小值的时候判断一下即可。
会不会一次删很多个而影响时间呢?不会。考虑边为M,因而将点加入的次数一定<=M(注意一个点虽然有可能被反复加入又删掉很多次,但是这个点作为一个特定的边到达的点只会被加入1次),那么删除也最多删除M次,因此不会影响时间。
时间复杂度O((N+M)logN)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define ll long long #define mod 1000000007 #define N 500005 using namespace std; int n,m,tot,k,fst[N],pnt[N],nxt[N],etr[N]; bool bo[N]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } void add(int x,int y){ pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot; } priority_queue<int,vector<int>,greater<int> > q; int main(){ int cas=read(); while (cas--){ n=read(); m=read(); k=read(); int i; tot=0; for (i=1; i<=n; i++){ bo[i]=1; fst[i]=etr[i]=0; } for (i=1; i<=m; i++){ int u=read(),v=read(); add(u,v); etr[v]++; } for (i=1; i<=n; i++) if (etr[i]<=k){ bo[i]=0; q.push(i); } int cnt=0; ll sum=0; while (!q.empty()){ while (etr[q.top()]>k){ bo[q.top()]=1; q.pop(); } int x=q.top(),p; q.pop(); k-=etr[x]; cnt++; sum=(sum+(ll)cnt*x)%mod; etr[x]=0; for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (etr[y]){ etr[y]--; if (etr[y]<=k && bo[y]){ bo[y]=0; q.push(y); } } } } printf("%I64d\n",sum); } return 0; }
第一场bestcoder,打了rank4,看起来还好但是。。实际上不太好啊。。div1的题目还没有看过,就不写了。
by lych
2016.3.5