社区讨论

求助,注释齐全

CF213E Two Permutations参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@lwvxgtzi
此快照首次捕获于
2024/06/01 17:45
2 年前
此快照最后确认于
2024/06/01 19:48
2 年前
查看原帖
问题可能出在关于base上,当base为10时,可以通过#14,当base为13331时,不能通过#14
CPP
#include<iostream>
#include<map>
#define int long long
using namespace std;
const int N=200010;
const int base=13331;
const int P=1000000007;
map<int,int> mp;
int QWQ=0;
struct info
{
    int sum,cnt;//和 和 数的个数
};
struct node
{
    int tag;
    info v;
}tr[N*4];
int n,m,a[N],b[N],in,h[N],pos[N],tmp;
int powq(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%P;
        a=a*a%P;
        b=b>>1;
    }
    return ans;
}
info merge(info a,info b)
{
    info c;
    c.sum=(a.sum+b.sum)%P;
    c.cnt=a.cnt+b.cnt;
    return c;
}
void update(int x)
{
    tr[x].v=merge(tr[x*2].v,tr[x*2+1].v);
}
void maketag(int x,int k,int L,int r)
{
    tr[x].v.sum=tr[x].v.sum*k%P;
    tr[x].tag=tr[x].tag*k%P;
}
void pushdown(int x,int L,int R)
{
    if(L==R)
        return;
    int mid=(L+R)/2;
    maketag(x*2,tr[x].tag,L,mid);
    maketag(x*2+1,tr[x].tag,mid+1,R);
    tr[x].tag=1;
}
void modify(int x,int l,int r,int k,int L,int R)//区间乘线段树
{
    pushdown(x,L,R);
    if(l==L&&R==r)
    {
        maketag(x,k,L,R);
        return;
    }
    int mid=(L+R)/2;
    if(r<=mid)
        modify(x*2,l,r,k,L,mid);
    else if(l>=mid+1)
        modify(x*2+1,l,r,k,mid+1,R);
    else
    {
        modify(x*2,l,mid,k,L,mid);
        modify(x*2+1,mid+1,r,k,mid+1,R);
    }
    update(x);
}
void modify(int x,int pos,int k,int L,int R)//单点赋值线段树
{
    pushdown(x,L,R);
    if(L==R)
    {
        tr[x].v.sum=k;
        tr[x].v.cnt=(k!=0);
        return;
    }
    int mid=(L+R)/2;
    if(pos<=mid)
        modify(x*2,pos,k,L,mid);
    else
        modify(x*2+1,pos,k,mid+1,R);
    update(x);
}
info find(int x,int l,int r,int L,int R)
{
    pushdown(x,L,R);
    if(l==L&&r==R)
        return tr[x].v;
    int mid=(L+R)/2;
    if(r<=mid)
        return find(x*2,l,r,L,mid);
    if(l>=mid+1)
        return find(x*2+1,l,r,mid+1,R);
    return merge(find(x*2,l,mid,L,mid),find(x*2+1,mid+1,r,mid+1,R));
}
void built(int x,int l,int r)
{
    tr[x].tag=1;
    if(l==r)
        return;
    int mid=(l+r)/2;
    built(x*2,l,mid);
    built(x*2+1,mid+1,r);
    update(x);
}
signed main()
{
    cin>>n>>m;
    h[0]=1;
    int now=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        now=(now*base+a[i])%P;
        h[i]=h[i-1]*base%P;
        tmp=(tmp+h[i-1])%P;
    }//哈希
    
    built(1,0,m+1);//建树,将所有标记设为1
    for(int i=0;i<=m-n;i++)
        mp[(now+i*tmp%P)%P]=1;//记录a数组所有可能值
    in=powq(base,P-2);//除数
    for(int i=1;i<=m;i++)
    {
        cin>>b[i];
        pos[b[i]]=i;
    }
    
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int x=pos[i];
        modify(1,0,x-1,base,0,m+1);
        int cnt=find(1,x+1,m+1,0,m+1).cnt;
        modify(1,x,h[cnt]*i%P,0,m+1);
    }
    if(mp[find(1,0,m+1,0,m+1).sum%P])
        ans++;
    
    for(int i=n+1;i<=m;i++)
    {
        int x=pos[i-n];
        modify(1,0,x-1,in,0,m+1);//除以前面的数
        modify(1,x,0,0,m+1);//去掉此数
        x=pos[i];
        modify(1,0,x-1,base,0,m+1);//前面统一乘
        int cnt=find(1,x+1,m+1,0,m+1).cnt;//后面的个数
        modify(1,x,h[cnt]*i%P,0,m+1);//加上这一位
        if(mp[find(1,0,m+1,0,m+1).sum%P])
            ans++;
    }
    cout<<ans;
}
/*
4 8
2 4 1 3 
3 6 8 5 4 2 7 1 
*/

回复

0 条回复,欢迎继续交流。

正在加载回复...