杭電多校第五場1009 (hdu7020


題意:

給一個數組a,求區間內眾數的數字個數大於區間長度一半的區間個數。

如眾數是ai,ai個數>(r-l+1)/2符合題意。

思路:

因為我們每次只要看眾數,所以可以根據出現的每個數來做。

對於一個數cnt[i],如果他在原串里的這個位置出現了,那就讓這個位置為1,否則為-1。

那么對於這個東西我們就可以求前綴和,如果sum[i]-sum[j]>0,說明這段區間里的這個數比其他數總和多。

所以就變成了對於上面定義的這樣一個數組,求前綴和sum[i]>sum[j]的個數(i>j)

定義兩個數組f1[sum]為前綴和為sum的點的個數。

f2[sum]為差分數組來維護f1。

對於1我們只需要線性掃描+維護就行了。

特殊情況是對於前綴和為當前最小時的連續-1,因為這個時候不會產生新解,所以可以利用剛才的f2數組來做差分,快速實現對於f1某一段的+1

注意點:這里初始時有一個前綴和為0,但是不能直接用進去,因為后續如果到過負數,那么開始i=0時的0是不能被計算進后面的答案里的。

因此維護幾個值的時候要前移一下,先計算這個點之前上一次的信息,來內含i=0時的信息。

下附代碼:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 vector<ll> cnt;
 5 vector<ll> G[1000005];
 6 ll res,n,a[1000005];
 7 ll flag[1000005];
 8 ll find(ll x){
 9     ll ans=0;
10     ll sum=0,minn=0;
11     unordered_map<ll,ll> f1,f2;
12     G[x].push_back(n+1);
13     ll k=0;
14     for (ll i=1; i<=n; i++){
15         if (i>G[x][k]) k++;
16         if (a[i]!=x && sum==minn){
17             ll len=G[x][k]-i-1;
18             f2[sum+1]--;
19             f2[sum-len]++;
20             i=G[x][k]-1;
21             sum=sum-len-1;
22         }
23         else if (a[i]==x) {
24             f1[sum]=f1[sum]+f2[sum];
25             f2[sum+1]+=f2[sum];
26             f2[sum]=0;
27             f1[sum]++;
28             ans+=f1[sum];
29             res+=ans;
30             sum++;
31             
32         }
33         else {
34             f1[sum]++;
35             sum--;
36             ans-=f1[sum];
37             res+=ans;
38         }
39         if (sum<minn) minn=sum;
40     }
41 }
42 int main(){
43     ll T;
44     scanf("%lld",&T);
45     while (T--){
46         scanf("%d",&n);
47         cnt.clear();
48         memset(flag,0,sizeof(flag));
49         for (ll i=1; i<=n; i++){
50             scanf("%lld",&a[i]);
51             if (!flag[a[i]]) cnt.push_back(a[i]),flag[a[i]]=1;
52             G[a[i]].push_back(i);
53         }
54         res=0;
55         for (auto i:cnt){
56             find(i);
57             G[i].clear();
58         }
59         printf("%lld\n",res);
60     }
61 }
View Code

 

 

賽場上看到ai的范圍,有因為題目性質提煉出來是看眾數的個數,所以其實只要看一個數就行了。

自然而然想到能不能枚舉每一個出現的ai,然后快速維護出個數大於一半的區間數。

當時時間復雜度搞錯了,感覺前綴和會T,但是其實這是個只有1和-1的前綴和,可以通過差分數組跳過一段-1來優化。

下次抓到靈感還是要多挖掘一下,不能輕易否決

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM