【uva 12174】Shuffle(算法效率--滑动窗口)
题意:假设一种音乐播放器有一个乱序的功能,设定每播放S首歌为一个周期,随机播放编号为1~S的歌曲。现在给一个长度为N的部分播放记录,请统计下次随机排序所发生的时间的可能性种数。(1≤S,N≤100000)
解法:由“连续的S个数”想到滑动窗口。O(n)循环一次,每次判断一个周期的[i-S+1,i]是否可行,记录入tf[i]。最后O(n)枚举第一个“窗口”的初始结束位置来得到可能性种数。
实现:在N个数后另外添加S-1个与之前都互不相同的数,以补全最后几个数的周期。当然,像一开始的几个数一样特判也可以。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 using namespace std; 7 const int N=100010,D=100010; 8 9 int a[2*N],v[2*N]; 10 bool tf[2*N]; 11 12 int main() 13 { 14 int T,n,s; 15 int i,j,k,tot; 16 scanf("%d",&T); 17 while (T--) 18 { 19 scanf("%d%d",&s,&n); 20 memset(tf,0,sizeof(tf)); 21 memset(v,0,sizeof(v)); 22 for (i=1;i<=n;i++) scanf("%d",&a[i]); 23 for (i=1;i<s;i++) a[n+i]=s+i; 24 tot=0; 25 for (i=1;i<n+s;i++) 26 { 27 if (v[a[i]]) 28 { 29 k=v[a[i]]; 30 for (j=v[a[i]];j>=i-tot;j--) 31 v[a[j]]=0; 32 tot=i-k-1; 33 } 34 if (tot==s) v[a[i-tot]]=0,tot--; 35 tot++,v[a[i]]=i; 36 if (tot==s) tf[i]=true; 37 if (i<s && tot==i) tf[i]=true; 38 } 39 tot=0; 40 for (i=1;i<=s;i++) 41 { 42 bool ok=true; 43 for (j=i;j<n+s;j+=s) 44 if (!tf[j]) {ok=false;break;} 45 if (ok) tot++; 46 } 47 printf("%d\n",tot); 48 } 49 return 0; 50 }
另外,我几天前按紫书说的“直接一点”的方法:据相同的数的相邻出现排除一些非法区间,利用这些并集得出答案。打了很久,调了很久,但一直WA~(搞得我这之后去做了几题图论了。qwq)求正解~
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 using namespace std; 7 const int N=100010,D=100010; 8 //Shuffle 2 WA 9 int a[N],last[N],first[N]; 10 int mmin(int x,int y) {return x<y?x:y;} 11 int mmax(int x,int y) {return x>y?x:y;} 12 int main() 13 { 14 int T,n,s; 15 scanf("%d",&T); 16 while (T--) 17 { 18 scanf("%d%d",&s,&n); 19 for (int i=1;i<=s;i++) 20 last[i]=first[i]=-s; 21 int l=s+1,r=0,x,ans=s; 22 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 23 for (int i=1;i<=n;i++) 24 { 25 if (first[a[i]] && i-first[a[i]]<s+1) {ans=0;break;} 26 { 27 int t=i-last[a[i]]; 28 if (t<=s) 29 { 30 int ll=(i+1)%s,rr=last[a[i]]%s; 31 if (ll>rr) x=ll,ll=rr,rr=x; 32 l=mmin(l,ll),r=mmax(r,rr); 33 } 34 } 35 first[a[i]]=last[a[i]], 36 last[a[i]]=i; 37 } 38 if (ans && l<=r) ans-=r-l+1; 39 if (s==1) ans=1; 40 printf("%d\n",ans); 41 } 42 return 0; 43 }