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)$

 

posted @ 2021-07-23 20:25  guapisolo  阅读(52)  评论(0编辑  收藏  举报