1. 题目描述
有长度为$n in [1, 10^5]$的序列,表示一个打乱的循环排列,即每当$[1 cdots n]$中的数字全部出现后,再重新产生一个随机的覆盖$[1 cdots n]$的序列。给定的序列并不是一个完整的循环序列,而是一个子序列。求完整的循环序列共有多少可能?
2. 基本思路
这是《算法竞赛入门经典》的原题,主要思路书里写的很清楚——利用滑动窗口确定每个位置开始是否包含一个循环节。
数据量很大,因此需要对位置进行预处理。同时,对前n个位置进行枚举,判断是否可以作为新的循环节的开始位置。滑动窗口效率很高,可以在$O(n)$时间复杂度进行预处理,算法的整体复杂度也是$O(n imes T)$的。
3. 代码
1 /* 2774 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 #define INF 0x3f3f3f3f 44 #define mset(a, val) memset(a, (val), sizeof(a)) 45 46 const int maxn = 1e5+15; 47 int a[maxn]; 48 int c[maxn]; 49 bool valid[maxn], visit[maxn]; 50 int n, m; 51 52 void init() { 53 int cnt = 0; 54 55 memset(c, 0, sizeof(c)); 56 // handle [0,n-1] 57 valid[0] = true; 58 rep(i, 0, n) { 59 if (i >= m) { // n >= m 60 ++cnt; 61 continue; 62 } 63 64 if (c[a[i]] > 0) { 65 valid[0] = false; 66 } else { 67 ++cnt; 68 } 69 70 ++c[a[i]]; 71 } 72 73 for (int i=1,j=n; i<m; ++i,++j) { 74 if (--c[a[i-1]] == 0) 75 --cnt; 76 if (j>=m || c[a[j]]==0) 77 ++cnt; 78 if (j < m) 79 ++c[a[j]]; 80 81 valid[i] = cnt==n; 82 } 83 84 // handle segment begin with i 85 memset(c, 0, sizeof(c)); 86 visit[0] = true; 87 88 rep(i, 0, n) { 89 if (i>=m || c[a[i]]==0) { 90 ++c[a[i]]; 91 visit[i+1] = true; 92 } else { 93 rep(j, i+1, n) 94 visit[j] = false; 95 break; 96 } 97 } 98 } 99 100 void solve() { 101 init(); 102 103 int ans = 0; 104 105 rep(i, 0, n) { 106 if (visit[i]) { 107 int tmp = 1; 108 for (int j=i; j<m; j+=n) { 109 if (!valid[j]) { 110 tmp = 0; 111 break; 112 } 113 } 114 ans += tmp; 115 } else { 116 break; 117 } 118 } 119 120 printf("%d ", ans); 121 } 122 123 int main() { 124 ios::sync_with_stdio(false); 125 #ifndef ONLINE_JUDGE 126 freopen("data.in", "r", stdin); 127 freopen("data.out", "w", stdout); 128 #endif 129 130 int t; 131 132 scanf("%d", &t); 133 while (t--) { 134 scanf("%d%d",&n,&m); 135 rep(i, 0, m) 136 scanf("%d", &a[i]); 137 solve(); 138 } 139 140 #ifndef ONLINE_JUDGE 141 printf("time = %ldms. ", clock()); 142 #endif 143 144 return 0; 145 }