首页 > 其他分享 >Codeforces 722 F Cyclic Cipher 题解 (同余方程,two-pointers)

Codeforces 722 F Cyclic Cipher 题解 (同余方程,two-pointers)

时间:2022-11-14 11:37:01浏览次数:82  
标签:方程 Cyclic int 题解 pointers 联立 define rep 同余

题目链接

前两天做过一个题意类似但做法不类似的题 在这里

首先做这道题需要一个结论:(一元)同余方程组有解的充要条件是方程组中的所有方程两两联立有解。证明 两个同余方程联立有解就用裴蜀定理判一下就行了。不用这个结论的话需要用CRT和一些数据结构解决,但是非常麻烦。

依次枚举每种数字i,尝试算出最长的全是i的子串。把n个序列中含有i的找出来,它们在所有n个中构成了一些连续段。这些连续段的长度之和是\(O(nk)\)的。对于每个连续段,求出这个段内部最长的全是i的子串。考虑从左到右枚举一个连续段中的每个位置r,算出以r为子串的右端点,左端点最左可以到哪里。令这个连续段中第j个位置对应的序列长度为\(N_j\),这个序列中i所在的位置为\(A_j\)(下标从0开始),则连续段中的每个位置都对应一个同余方程\(x \equiv A_j (mod \ N_j)\)。其实我们就是要找出最小的l,满足[l,r]中的同余方程联立成方程组是有解的。发现随着r的增加,l不会减少,所以可以用two-pointers。我们要做的是在当r增加1时,快速找出现在[l,r]中与位置r的方程联立无解的所有方程,并将其删除,同时增加l。发现如果两个方程N相同但A不同,联立一定无解,所以每时每刻,[l,r]中每个N只会有1种对应的A。所以每次r增加1,我们就枚举所有N(一共40种),如果某个N对应的A表示的方程 与 r所对应的方程 联立无解,那么就把所有\(N_j\)等于这个N的方程删除。每种N对应的所有方程可以用vector维护。由于每个方程的N和A的值域都是40,所以可以预处理任意两种方程是否联立无解。

总复杂度\(O(nk^2+k^4logk)\)。(\(k^4logk\)是预处理复杂度)

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back

void fileio()
{
  #ifdef LGS
  freopen("in.txt","r",stdin);
  freopen("out.txt","w",stdout);
  #endif
}
void termin()
{
  #ifdef LGS
  std::cout<<"\n\nPROGRAM TERMINATED";
  #endif
  exit(0);
}

using namespace std;

int n,m,ans[100010],sz[100010];
bool bad[42][42][42][42];//a1,n1,a2,n2
vector <pii> poss[100010];
vector <int> pss[50];

void solve(int ii)
{
  rep(i,45) pss[i].clear();
  rep(i,poss[ii].size())
  {
    int p=i;while(p+1<poss[ii].size()&&poss[ii][p+1].fi==poss[ii][p].fi+1) ++p;
    int cur=i;
    set <int> st;
    for(int ed=i;ed<=p;++ed)
    {
      st.insert(ed);
      int mxdel=-1,kk=sz[poss[ii][ed].fi],aa=poss[ii][ed].se;
      repn(j,40) if(pss[j].size())
      {
        int kkk=j,aaa=poss[ii][pss[j][0]].se;
        if(bad[aa][kk][aaa][kkk])
        {
          mxdel=max(mxdel,pss[j].back());
          pss[j].clear();
        }
      }
      pss[kk].pb(ed);
      while(*st.begin()<=mxdel) st.erase(st.begin());
      ans[ii]=max(ans[ii],(int)st.size());
    }
    i=p;
  }
}

int main()
{
  fileio();
  freopen("hypochondriac.in","r",stdin);
  freopen("hypochondriac.out","w",stdout);

  rep(i,40) for(int j=i+1;j<=40;++j) rep(ii,40) for(int jj=ii+1;jj<=40;++jj)
  {
    LL dv=__gcd(j,jj);
    if(abs(i-ii)%dv!=0) bad[i][j][ii][jj]=true;
  }

  cin>>n>>m;
  rep(i,n)
  {
    int x,y;
    scanf("%d",&x);sz[i]=x;
    rep(j,x)
    {
      scanf("%d",&y);
      poss[y].pb(mpr(i,j));
    }
  }
  repn(i,m) if(poss[i].size()) solve(i);
  repn(i,m) printf("%d\n",ans[i]);

  termin();
}

标签:方程,Cyclic,int,题解,pointers,联立,define,rep,同余
From: https://www.cnblogs.com/legendstane/p/codeforces-cf-722-f-Cyclic-Cipher-solution-crt-two-p

相关文章

  • CF1650G 『Counting Shortcuts』 题解
    从洛谷博客那里搬过来的(图论专题本来打算先挑最简单的做,结果做了两个多小时(题意就是让你找从起点\(s\)到终点\(t\)的最短路以及次短路个数,本题次短路长度指的是最短......
  • Codeforces 833 题解
    A\(n\)是奇数时恰好可以用完,\(n\)是偶数时多出来的一块没用,所以直接输出\((n+1)/2\)即可。B每个字符出现次数都小于等于字符总数,令\(\Sigma\)是字符集大小,那显然......
  • CF1292E Rin and The Unknown Flower 题解
    IO交互题fflush(stdout)害人不浅!!1注意到如果我们发起询问C和O就可以花费2的代价知道整个串,不过代价过高,所以我们考虑减小点代价。考虑发起询问CO,CH,CC,这样我......
  • TheNameCalculator题解
    TheNameCalculator题解题目链接:TheNameCalculator题解首先看程序开启的保护,有Canary和NX栈不可执行。IDA打开程序,shift+F12查看字符串,发现有"Hereisyourflag:"。点......
  • 833——B题题解
    题目链接题目大意:给一串字符串(只包含0~9),定义一个最优子串的定义:如果该子串同字符种类数大于最最多字符出现数,那么这个子串可以被称为最优子串。解题思路:大眼一看这个数......
  • [ARC086F] Shift and Decrement 题解
    linkSolution一个简易的贪心想法是我们肯定是对于一个相同的序列求出操作到它的最小操作次数,看能否\(\leK\)。注意到我们在第\(x\)次A操作后进行\(-1\)操作相当于......
  • 833(DIV2)——C题题解
    题目链接题目大意:给定n个数,你可以对数值为0的数改变其为任意值,问最后前缀和为0的个数的最大值。思路:这题比较可惜,自己的思路没有问题,但是他少了一些东西。对数组进行前......
  • LG_P4588 [TJOI2018] 数学计算 题解
    LuoguP4588题解这个玩意还是挺好想到的,也不难看出他是一个线段树。没想到可以评上蓝。考虑每次操作对于答案的贡献。由于\(x=1\),所以我们相当于是在维护一堆数的积,初始......
  • DTOJ 3498 无限剑制 题解
    题面题目链接题解想了好久,其实很水tt想写题解主要是因为这题题面是Fate很有意思我们注意到“所有\(v_i\)值域在\([1,5]\)”这个部分分,这种情况下,初始的不同情......
  • DTOJ 5932 Counting 题解
    题目链接portal题解认识到了生成函数很好用,于是摆了一篇题解10分直接dp,\(f_{i,j}\)表示走了\(i\)步之后,当前位置在\(j\)的方案数然后就有状态转移方程\(f_{i,......