set
发现序列后一位必然是
A
A
A中
x
x
x后第一个
>
A
x
>A_x
>Ax的位置
y
y
y,类似于树上
x
→
f
a
x
x\to fa_x
x→fax的关系。
所以单调栈建数,树剖维护单调修改,链查询,特判一下即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+12;
int n,m,a[N],w[N],rt;
int f[N],son[N],sz[N],top[N],dfn;
int dep[N],df[N],rv[N];
int head[N],to[N],nxt[N],tot;
inline char gc()
{
static char buf[(1<<15)];static int p1=0,p2=0;
if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
return (p1==p2)?EOF:buf[p1++];
}
char cp;
template<class T>inline void rd(T &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
template<class T>inline void prit(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) prit(x/10);putchar('0'+(x%10));
}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
void dfs1(int x)
{
int i,j;sz[x]=1;son[x]=0;
dep[x]=dep[f[x]]+1;
for(i=head[x];i;i=nxt[i]){
j=to[i];dfs1(j);
sz[x]+=sz[j];
if((!son[x]) || sz[j]>sz[son[x]]) son[x]=j;
}
}
void dfs2(int x,int tpo)
{
df[x]=++dfn;rv[dfn]=x;top[x]=tpo;
if(!son[x]) return;
dfs2(son[x],tpo);int i,j;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==son[x]) continue;
dfs2(j,j);
}
}
inline int LCA(int x,int y)
{
for(;top[x]!=top[y];x=f[top[x]])
if(dep[top[x]]<dep[top[y]]) swap(x,y);
if(dep[x]<dep[y]) swap(x,y);
return y;
}
namespace SGT{
#define mid ((l+r)>>1)
#define lc k<<1
#define rc k<<1|1
#define lcc lc,l,mid
#define rcc rc,mid+1,r
ll slf[N<<2],af[N<<2],z,chg[N];//self as_fat
void build(int k,int l,int r)
{
if(l==r){slf[k]=(ll)w[rv[l]];return;}
build(lcc);build(rcc);
slf[k]=slf[lc]+slf[rc];
}
void ad(int k,int l,int r,int pos)
{
slf[k]+=z;af[k]+=z;
if(l==r) return;
if(pos<=mid) ad(lcc,pos);
else ad(rcc,pos);
}
ll query(int k,int l,int r,int L,int R)
{
if(L<=l && r<=R) return slf[k]+af[k];
if(R<=mid) return query(lcc,L,R);
if(L>mid) return query(rcc,L,R);
return query(lcc,L,R)+query(rcc,L,R);
}
inline ll ask(int x,int y)
{
ll re=0LL;
for(;top[x]!=top[y];x=f[top[x]]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
re+=query(1,1,n,df[top[x]],df[x]);
}
if(dep[x]<dep[y]) swap(x,y);
re+=query(1,1,n,df[y],df[x]);
return re;
}
void sol()
{
int op,x,y,sme;
rd(op);rd(x);rd(y);
if(op==1){z=y;ad(1,1,n,df[x]);chg[x]+=z;return;}
if(dep[x]<dep[y]) swap(x,y);sme=LCA(x,y);
if(sme==rt || (sme==y && f[y]==rt)){puts("?");return;}
ll re=ask(x,y);
if(sme!=x && sme!=y){
re-=(chg[x]+chg[y]);re+=chg[sme];
if(f[sme]!=rt) re+=chg[f[sme]];
}else{
re-=chg[x];sme=f[sme];re+=((chg[sme]<<1)+w[sme]);
if(f[sme]!=rt) re+=chg[f[sme]];
}
prit(re);putchar('\n');
}
}
int stk[N],stp;
int main(){
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
int i;rd(n);rd(m);
for(i=1;i<=n;++i){
rd(a[i]);
for(;stp>0 && a[stk[stp]]<a[i];--stp){
lk(i,stk[stp]);f[stk[stp]]=i;
}
stk[++stp]=i;
}
for(i=1;i<=n;++i) rd(w[i]);
n++;rt=n;
for(;stp>0;--stp) {lk(rt,stk[stp]);f[stk[stp]]=rt;}
dfs1(rt);dfs2(rt,rt);
SGT::build(1,1,n);
for(;m;--m) SGT::sol();
fclose(stdin);fclose(stdout);
return 0;
}
blue
循环右移的循环节 x ≤ n x\leq n x≤n
双射函数的置换循环节 l c m ( l e n i ) , ∑ l e n i = 26 lcm(len_i),\sum len_i=26 lcm(leni),∑leni=26(打表发现 ≤ 1260 \leq 1260 ≤1260)
所以整体循环节 ≤ 1260 n \leq 1260n ≤1260n,模数是int级别的
固定左移位数 x x x,操作次数 k k k:
a ⋅ k ≡ x ( m o d n ) , x ≡ Δ ( p o s t i − p o s s i + x ) ( m o d l e n b e l t i ) a·k\equiv x\pmod{n},x\equiv \Delta(pos_{t_i}-pos_{s_{i+x}})\pmod{len_{bel_{t_i}}} a⋅k≡x(modn),x≡Δ(posti−possi+x)(modlenbelti)
EXCRT求解
26
+
1
26+1
26+1个线性同余方程的解即可。
(其中
p
o
s
t
i
pos_{t_i}
posti表示字符
t
i
t_i
ti在环中的位置,
b
e
l
t
i
bel_{t_i}
belti表示字符
t
i
t_i
ti所属环)
可以匹配上显然有两个前提条件:
- b e l t i = b e l s t i + x bel_{t_i}=bel_{s_{t_i+x}} belti=belsti+x
- 对于每一个环,环上所有位置差相同
暴力求解是 O ( n 2 ) O(n^2) O(n2)的(因为每个位置都会列一个方程)
发现本质上只有 26 + 1 26+1 26+1个方程,考虑优化(下面的我就没想到了QWQ:
- t i → b e l t i , s i → b e l s i t_i\to bel_{t_i},s_{i}\to bel_{s_i} ti→belti,si→belsi,KMP求出所有匹配上的位置,满足条件1
- 对于每个环,每个位置与前驱最近的属于同一个环的字符所处环位置做差分,KMP求匹配,满足条件2
只需要对于所有可行位置求解,总时间复杂度 O ( 27 n log n ) O(27n\log n) O(27nlogn)
我的 n 2 n^2 n2暴力:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e5+20;
const int inf=0x7f7f7f7f;
//max lcm(1...26) 1260
//max (1260,n) 251998740
int n,A,B,f[27],ans=inf,g;
char s[N<<1],t[N<<1];
ll X,Y;
char cp;
template<class T>inline void rd(T &x)
{
cp=getchar();x=0;int f=0;
for(;!isdigit(cp);cp=getchar()) if(cp=='-') f=1;
for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
if(f) x=-x;
}
inline void dn(int &x,int y){if(y<x) x=y;}
inline int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
inline void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b) {x=1;y=0;return;}
exgcd(b,a%b,y,x);y-=(a/b)*x;
}
namespace CRT{
struct pr{int val,p;}e[N],ex[N];
int dr[27],nw,md,num;
inline int mk(int n)
{
int i,res,rp,g,j;num=0;
memset(dr,0xff,sizeof(dr));
for(i=1;i<=n;++i) if(e[i].p<=26){
if(dr[e[i].p]==-1) dr[e[i].p]=e[i].val,ex[++num]=e[i];
else if(e[i].val!=dr[e[i].p]) return inf;
}else ex[++num]=e[i];
nw=0;md=0;
for(i=1;i<=num;++i){
rp=ex[i].p;
if((!nw)&&(!md)) {nw=ex[i].val;md=rp;continue;}
res=(ex[i].val%rp-nw%rp);if(res<0) res+=rp;
g=gcd(md,rp);if(res%g) return inf;res/=g;
exgcd(md%rp,rp,X,Y);X%=rp;if(X<0) X+=rp;
j=md;md=md/g*rp;res=(ll)res*j%md;
nw=(nw+(ll)X*res%md)%md;
}
if(nw==0) return md;
return nw;
}
}
int bel[27],rk[27],cir,len[27];
vector<int>hv[27];
inline void pre()
{
int i,j;
for(i=0;i<26;++i) if(!bel[i]){
bel[i]=++cir;len[cir]=1;
rk[i]=0;hv[cir].pb(i);
for(j=f[i];j!=i;j=f[j]){
bel[j]=cir;hv[cir].pb(j);
rk[j]=len[cir]++;
}
}
for(i=0;i<26;++i){
j=bel[i];bel[i]=0;
f[i]=hv[j][(rk[i]+B)%len[j]];
}
cir=0;
for(i=0;i<26;++i) if(!bel[i]){
bel[i]=++cir;len[cir]=1;
rk[i]=0;
for(j=f[i];j!=i;j=f[j]){
bel[j]=cir;rk[j]=len[cir]++;
}
}
}
inline int nt(int x){return x<=n?x:x-n;}
inline int cal(int dlt)
{
int i,j,x,y;
for(i=1;i<=n;++i){
x=t[i];y=s[nt(i+dlt)];j=bel[x];
if(j!=bel[y]) return inf;j=len[j];
CRT::e[i].p=j;
CRT::e[i].val=(rk[x]-rk[y]+j)%j;
}
if(A){
int md=n/g;dlt/=g;
exgcd(A/g,md,X,Y);
X=X%md;if(X<0) X+=md;
CRT::e[n+1].p=md;
CRT::e[n+1].val=(ll)dlt*X%md;
return CRT::mk(n+1);
}
return CRT::mk(n);
}
int main(){
freopen("blue.in","r",stdin);
freopen("blue.out","w",stdout);
int i,j;
rd(n);rd(A);rd(B);A%=n;
scanf("%s",s);
for(i=0;i<26;++i) f[i]=s[i]-'a';
scanf("%s%s",s+1,t+1);
if(A==0 && B==0){
for(i=1;i<=n;++i) if(s[i]!=t[i]) break;
printf((i>n)?"1":"-1");return 0;
}
pre();if(A) g=gcd(A,n);
for(i=1;i<=n;++i) s[i]-='a',t[i]-='a';
if(A==0) ans=cal(0);
else if((ll)(n/g)*n<=9000001LL) for(i=0;i<n;i+=g) dn(ans,cal(i));
if(ans<inf) printf("%d",ans);
else printf("-1");
fclose(stdin);fclose(stdout);
return 0;
}
std
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
int ans=2147483647,z,y,x,M;//ans will not be greater than n*1260,otherwise ans is -1
int nxt[200050],la,lb,f[35],lis[200050],lcnt,np[400050],bel[35],a,b;
int id[35],clen[35],nb[35],tmp,cnt,l1[200050],l2[400050],lst[35],ep[35];
char s[400050],t[200050],s1[35];
bool vis[400050],pvis[400050];
int gcd(int a,int b){return !(a%b)?b:gcd(b,a%b);}
void dfs(int u,int lb,int nu){
bel[u]=lb;
id[u]=nu;
tmp++;
if (!bel[f[u]])dfs(f[u],lb,nu+1);
}
void kmp(){
nxt[0]=-1;int j=-1;
for (int i=1;i<lb;i++){
while (j!=-1&&l1[j+1]!=l1[i])j=nxt[j];
if (l1[j+1]==l1[i])j++;
nxt[i]=j;
}
}
void getp(){
int j=-1;
for (int i=0;i<la;i++){
while (j!=-1&&l2[i]!=l1[j+1])j=nxt[j];
if (l1[j+1]==l2[i])j++;
if (j==lb-1)vis[i]=1,j=nxt[j];
}
}
void inv(ll a,ll b) {
if (a%b==0){z=0;y=1;return;}
inv(b,a%b);
ll r=z;
z=y,y=r-a/b*y;
}
bool solve(ll A,ll k,int m){
int d;
d=gcd(A,m),m/=d,A/=d;
if ((k%d))return 0;
k/=d;
inv(A,m);
k*=z;A=k-x;//k*z may greater than 2147483647
d=gcd(M,m);
if ((A%d))return 0;
inv(M/d,m/d);
int kp=A/d*1ll*z%(m/d);
x+=kp*M;
M*=m/d;
return 1;
}
int main(){
freopen("blue.in","r",stdin);
freopen("blue.out","w",stdout);
scanf("%d%d%d",&lb,&a,&b);
a%=lb;
la=lb*2;
scanf("%s",s1);
for (int i=0;i<26;i++)f[i]=s1[i]-'a';
for (int i=0;i<26;i++)if (!bel[i]){dfs(i,++cnt,1);clen[cnt]=tmp;nb[cnt]=b%tmp;tmp=0;}
scanf("%s%s",s,t);
for (int i=0;i<lb;i++)s[i+lb]=s[i];
for (int i=0;i<lb;i++)l1[i]=bel[t[i]-'a'];
for (int i=0;i<la;i++)l2[i]=bel[s[i]-'a'];
kmp();getp();//match with ring's num
memcpy(pvis,vis,sizeof pvis);
memset(vis,0,sizeof vis);
for (int i=0;i<lb;i++){
if (lst[l2[i]])l2[i]=(id[s[i]-'a']-lst[l2[i]]+clen[l2[i]])%clen[l2[i]];
else np[i]=1;
lst[bel[s[i]-'a']]=id[s[i]-'a'];
}
for (int i=0;i<lb;i++)if (np[i])l2[i]=(id[s[i]-'a']-lst[bel[s[i]-'a']]+clen[bel[s[i]-'a']])%clen[bel[s[i]-'a']];
for (int i=0;i<lb;i++)l2[i+lb]=l2[i];
memset(lst,0,sizeof lst);
memset(nxt,0,sizeof nxt);
memset(np,0,sizeof np);
memset(ep,-1,sizeof ep);
for (int i=0;i<lb;i++){
if (lst[l1[i]])l1[i]=(id[t[i]-'a']-lst[l1[i]]+clen[l1[i]])%clen[l1[i]];
else np[i]=1;
lst[bel[t[i]-'a']]=id[t[i]-'a'];
ep[bel[t[i]-'a']]=i;
}
for (int i=0;i<lb;i++)if (np[i])
l1[i]=(id[t[i]-'a']-lst[bel[t[i]-'a']]+clen[bel[t[i]-'a']])%clen[bel[t[i]-'a']];
kmp();getp();//match with ring's differences
int k;
for (int i=lb-1;i<la-1;i++)if (vis[i]&&pvis[i])lis[++lcnt]=(i-lb+1)%lb;
for (int i=1;i<=lcnt;i++){
x=0,M=1;
bool flag=1;//solve congruence equations
for (int j=1;j<=cnt&&flag;j++)if(ep[j]!=-1){
int pos=(lis[i]+ep[j])%lb;
k=(id[t[ep[j]]-'a']-id[s[pos]-'a']+clen[j])%clen[j];
if (!nb[j]){if (!k)continue;flag=0;continue;}
flag&=solve(nb[j],k,clen[j]);
}
if (!a){if (lis[i])continue;}
else flag&=solve(a,lis[i],lb);
if (!flag)continue;
x<=0?x+=M:0;
ans=std::min(ans,x);
}
if (ans>1e9)printf("-1\n");
else printf("%d\n",ans);
}
总结
以后T1这种签到题一定要快准狠的切了
T2其实就差一步KMP了,为什么我没有想到相对位置可以差分呢QWQ,难受