UVA - 12174 Shuffle (预处理+滑动窗口)
题意:已知歌单中的歌曲数目s,和部分的播放历史,问下一首可能播放的歌曲种数。
分析:
1、按照歌单数目s,将播放历史划分为几部分。
2、将播放历史的n首歌曲之前加上s首歌曲,之后加上s首歌曲,为防止标号重复,分别将其标号为100001 + i和200001 + i。
3、枚举这个新的序列中的每首歌,以s首为区间,区间开头为i,结尾为s + i - 1,若该区间里的数字不唯一,则不可能以该区间为标准划分,排除i%s这一划分可能。
4、判断区间里歌曲唯一的方法,记录每首歌出现次数,进入区间则加1,离开区间则减1,若区间长为s,里面每首歌都出现过1次,则此时sum一定为0,区间内是一种可行的播放顺序。
5、为排除之前s首和之后s首对歌曲唯一性判断的影响,只要初始化成之前的歌曲出现次数-1后不为1,之后的歌曲出现次数+1后不为2即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #include<iostream> #include<sstream> #include<iterator> #include<algorithm> #include<string> #include<vector> #include<set> #include<map> #include<stack> #include<deque> #include<queue> #include<list> #define lowbit(x) (x & (-x)) const double eps = 1e-8; inline int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a > b ? 1 : -1; } typedef long long LL; typedef unsigned long long ULL; const int INT_INF = 0x3f3f3f3f; const int INT_M_INF = 0x7f7f7f7f; const LL LL_INF = 0x3f3f3f3f3f3f3f3f; const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f; const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1}; const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1}; const int MOD = 1e9 + 7; const double pi = acos(-1.0); const int MAXN = 300000 + 10; const int MAXT = 10000 + 10; using namespace std; int a[MAXN]; map<int, int> mp; bool ans[MAXN]; int s, n; int solve(){ int sum = 0; for(int i = 1; i < n + s; ++i){ int et = s + i - 1; if(--mp[a[i - 1]] == 1) --sum; if(++mp[a[et]] == 2) ++sum; if(sum != 0) ans[i % s] = false; } int cnt = 0; for(int i = 0; i < s; ++i){ if(ans[i]){ ++cnt; } } return cnt; } int main(){ int T; scanf("%d", &T); while(T--){ mp.clear(); memset(a, 0, sizeof a); memset(ans, true, sizeof ans); scanf("%d%d", &s, &n); for(int i = 0; i < s; ++i){ a[i] = 100001 + i; ++mp[a[i]]; } for(int i = 0; i < n; ++i){ scanf("%d", &a[i + s]); } for(int i = 0; i < s; ++i){ a[s + n + i] = 200001 + i; } printf("%d\n", solve()); } return 0; }