掉大分
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 }
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)$