Shuffle UVA - 12174 尺取法

题目:题目链接

思路:见紫书,对具体操作方式还不是很理解,代码是从一个题解里看的,以后多回顾下,需要理解

代码:

 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 }

猜你喜欢

转载自www.cnblogs.com/fan-jiaming/p/9860519.html