【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
",tot);
48     }
49     return 0;
50 }
View Code

另外,我几天前按紫书说的“直接一点”的方法:据相同的数的相邻出现排除一些非法区间,利用这些并集得出答案。打了很久,调了很久,但一直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
",ans);
41     }
42     return 0;
43 }
WA
原文地址:https://www.cnblogs.com/konjak/p/6024311.html