题目:题目链接
思路:见紫书,对具体操作方式还不是很理解,代码是从一个题解里看的,以后多回顾下,需要理解
代码:
1 #include <iostream> 2 #include <cstring> 3 #include <set> 4 using namespace std; 5 6 const int N = 1e5 + 5; 7 8 int s, n, a[N], vis[N]; 9 bool flag[N]; 10 int ans; 11 12 void init() 13 { 14 cin >> s >> n; 15 int num = 0; 16 for (int i = 0; i < n; i++) 17 { 18 cin >> a[i]; 19 if (i < s) 20 { //对前面的s个进行分析 21 if (vis[a[i]]) 22 num++; //统计前s个中重复的数字 23 vis[a[i]]++; 24 } 25 } 26 27 for (int i = 0; i < n; i++) 28 { 29 //如果num=0,说明前s个中没有重复的数字,那么第一个数字可以作为循环的开始 30 if (num == 0) 31 flag[i] = true; 32 33 //窗口开始滑动 34 if (vis[a[i]] == 2) 35 num--; //如果此时最左边的数为重复了的数,num需要减1 36 vis[a[i]]--; 37 38 int k = i + s; //新数字进入滑动窗口 39 if (k >= n) 40 continue; 41 if (vis[a[k]]) 42 num++; //如果已经出现过 43 vis[a[k]]++; 44 } 45 } 46 47 bool judge(int x) 48 { 49 for (int i = x; i < n; i += s) 50 if (!flag[i]) 51 return false; 52 return true; 53 } 54 55 void solve() 56 { 57 memset(vis, 0, sizeof(vis)); 58 59 ans = 0; 60 for (int i = 0; i < s; i++) 61 { 62 if (judge(i)) 63 ans++; 64 if (i >= n) 65 continue; 66 //从左往右依次遍历,如果当前a[i]前面已经出现过,那么前面必须会有开头,此时必须结束循环 67 if (vis[a[i]]) 68 break; 69 vis[a[i]]++; 70 } 71 } 72 73 int main() 74 { 75 //freopen("D:\\txt.txt", "r", stdin); 76 int t; 77 cin >> t; 78 while (t--) 79 { 80 memset(flag, 0, sizeof(flag)); 81 memset(vis, 0, sizeof(vis)); 82 init(); 83 solve(); 84 cout << ans << endl; 85 } 86 return 0; 87 }
原文地址:https://www.cnblogs.com/fan-jiaming/p/9860519.html
时间: 2024-11-02 16:45:44