zoukankan      html  css  js  c++  java
  • 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} floor b
    $$
    我们把式子拆分一下,让问题变得有序
    $$
    p[k]=f[k]+g[k]\
    $$

    $$
    f[k]=sum_{i,jle 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]} floor a[i] \
    =f[k-1]+(k-1)a[k]-sum_{i=1}^{k-1}lfloor frac{a[k]}{a[i]} floor a[i]
    $$

    最后一项与前面的a[i]有关,我们从左往右处理,相当于每次向序列末尾推进一个a[k],接着计算它的贡献。a[i]会对a[k]在每隔ai的一段连续区间产生相同的贡献。对$[0,a[i])$产生0点,对$[a[i],2a[i])$产生a[i]点贡献。。。

    我们需要区间修改,单点查询,上线段树

    注意题目中的关键条件$a[i] e a[j]$,满足调和级数,那么即使我们暴力修改,也最多修改$O(mlogm)$个连续区间

    接着处理剩下的一部分贡献
    $$
    g[k]=sum_{i,jle 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]} floor a[k] \
    =g[k-1]+sum_{i=1}^{k-1}a[i]-sum_{i=1}^{k-1}lfloor frac{a[i]}{a[k]} floor a[k]
    $$
    还能用和上面相同的方法处理吗?答案是否定的,我们要对后面的式子**整除分块**计算贡献,而每次整除分块的复杂度是$O(sqrt{m})$,修改的区间个数是$O(msqrt{m})$,应该会被卡

    考虑讨论$lfloor frac{a[i]}{a[k]} floor$的取值,在$[0,a[k])$之间是0,在$[a[k],2a[k])$之间是1。。。

    对每个区间查询$a[i]$的和以及$a[i]$的出现次数!区间个数满足调和级数,也是$O(mlogm)$的

    单点修改,区间查询,上线段树

    总复杂度$O(mlogmlogn)$

  • 相关阅读:
    FluentValidation 验证框架笔记1
    AutoMapper 笔记1
    MediatR框架笔记1
    vscode调试python时提示无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称的解决方法
    Selenium使用自带浏览器自动化
    Selenium启动Chrome插件(Chrome Extensions)
    Gitee,Github 图片转直链
    CentOS 7.3 修改root密码 passwd: Authentication token manipulation error
    阿里云服务器 被入侵植入dhpcd导致cpu飙升100%问题
    Github 切换分支
  • 原文地址:https://www.cnblogs.com/guapisolo/p/15050695.html
Copyright © 2011-2022 走看看