CF1553X Harbour.Space Scholarship Contest 2021-2022 (Div. 1 + Div. 2)

掉大分

 

E

對於一個序列,把它排回去的最小次數是 $\sum置換環大小-1=錯位個數-置換環個數$

注意到m小於等於n/3。那麼最多修正2m個錯位。正確位置的個數必須大於等於n/3纔可能在m次內修正。

每個點正確位置只有一個。那麼整個序列最多有3個位置,以它們爲開頭滿足條件。找出這些位置再暴力驗證即可

 1 #include <queue>
 2 #include <bitset>
 3 #include <vector>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #define ll long long 
 8 using namespace std;
 9 const int maxn=3e5, N1=maxn+5;
10 
11 template <typename _T> void read(_T &ret)
12 {
13     ret=0; _T fh=1; char c=getchar();
14     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
15     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
16     ret=ret*fh;
17 }
18 
19 int T,m,n; 
20 int p[N1],cnt[N1];
21 int a[N1],vis[N1];
22 
23 int check(int to)
24 {
25     for(int i=1+to;i<=n;i++) a[i-to]=p[i];
26     for(int i=1;i<=to;i++) a[i+n-to]=p[i];
27     for(int i=1;i<=n;i++) vis[i]=0;
28     int tot=0;
29     for(int i=1,num,x;i<=n;i++)
30     {
31         num=0;
32         if(vis[i]) continue;
33         for(x=i;;x=a[x])
34         {
35             vis[x]=1; num++;
36             if(a[x]==i) break;
37         }
38         tot+=num-1;
39     }
40     return tot<=m;
41 }
42 
43 int main()
44 {
45     // freopen("a.in","r",stdin);
46     read(T);
47     while(T--)
48     {
49         read(n); read(m);
50         for(int i=1,x;i<=n;i++) 
51         {
52             read(p[i]);
53             x=i-p[i]; if(x<0) x+=n;
54             cnt[x]++;
55         }
56         int ans=0, pos[3]={0,0,0}, fl;
57         for(int i=0;i<n;i++) if(cnt[i]>=n/3)
58         {
59             fl=check(i);
60             if(fl) pos[ans++]=i;
61         }
62         printf("%d ",ans);
63         for(int i=0;i<ans;i++) printf("%d ",pos[i]);
64         puts("");
65         for(int i=1;i<=n;i++) cnt[i]=0;
66     }
67     return 0;
68 }
View Code

 

 

F

此題應用了一個經典的換掉mod的方法:
$$
a\ mod\ b=a-\lfloor \frac{a}{b} \rfloor b
$$
我們把式子拆分一下,讓問題變得有序
$$
p[k]=f[k]+g[k]\\
$$

$$
f[k]=\sum_{i,j\le k,j<i}a[i]\ mod\ a[j] \\
=f[k-1]+\sum_{i=1}^{k-1}a[k]\ mod\ a[i] \\
=f[k-1]+\sum_{i=1}^{k-1}a[k]-\lfloor \frac{a[k]}{a[i]} \rfloor a[i] \\
=f[k-1]+(k-1)a[k]-\sum_{i=1}^{k-1}\lfloor \frac{a[k]}{a[i]} \rfloor a[i]
$$

最後一項與前面的a[i]有關,我們從左往右處理,相當於每次向序列末尾推進一個a[k],接着計算它的貢獻。a[i]會對a[k]在每隔ai的一段連續區間產生相同的貢獻。對$[0,a[i])$產生0點,對$[a[i],2a[i])$產生a[i]點貢獻。。。

我們需要區間修改,單點查詢,上線段樹

注意題目中的關鍵條件$a[i]\ne a[j]$,滿足調和級數,那麼即使我們暴力修改,也最多修改$O(mlogm)$個連續區間

接着處理剩下的一部分貢獻
$$
g[k]=\sum_{i,j\le k,j<i}a[j]\ mod\ a[i] \\
=g[k-1]+\sum_{i=1}^{k-1}a[i]\ mod\ a[k] \\
=g[k-1]+\sum_{i=1}^{k-1}a[i]-\lfloor \frac{a[i]}{a[k]} \rfloor a[k] \\
=g[k-1]+\sum_{i=1}^{k-1}a[i]-\sum_{i=1}^{k-1}\lfloor \frac{a[i]}{a[k]} \rfloor a[k]
$$
還能用和上面相同的方法處理嗎?答案是否定的,我們要對後面的式子**整除分塊**計算貢獻,而每次整除分塊的複雜度是$O(\sqrt{m})$,修改的區間個數是$O(m\sqrt{m})$,應該會被卡

考慮討論$\lfloor \frac{a[i]}{a[k]} \rfloor$的取值,在$[0,a[k])$之間是0,在$[a[k],2a[k])$之間是1。。。

對每個區間查詢$a[i]$的和以及$a[i]$的出現次數!區間個數滿足調和級數,也是$O(mlogm)$的

單點修改,區間查詢,上線段樹

總複雜度$O(mlogmlogn)$

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章