noi2017 day1 题解

d1t1

用线段树维护区间是否全0/全1,叶子上压位维护对应位置的数位,加法首先对叶子加,如需进位则向右找到第一个不是全1的叶子+1,中间部分全1部分打上反转标记,减法同理。

#include<cstdio>
int _(){
    int x=0,f=1,c=getchar();
    while(c<48)c==‘-‘?f=-1:0,c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x*f;
}
const int N=1100127;
typedef unsigned int u32;
int n,_l,flag;
u32 _ans;
int mx;
struct node{
    node*lc,*rc;
    int rev;
    u32 _or,_and;
    void revs(){
        rev^=1;
        _or=~_or;
        _and=~_and;
    }
    void up(){
        _or=lc->_or|rc->_or;
        _and=lc->_and&rc->_and;
    }
    void dn(){
        if(rev){
            rev^=1;
            lc->revs();
            rc->revs();
        }
    }
    void find(int L,int R){
        if(L==R){
            _ans=_or;
            return;
        }
        int M=(L+R)>>1;
        dn();
        if(_l<=M)lc->find(L,M);
        else rc->find(M+1,R);
    }
    void inc(int L,int R){
        if(L==R){
            flag=(_and+_ans<_and);
            _and+=_ans;
            _or=_and;
            return;
        }
        int M=(L+R)>>1;
        dn();
        if(_l<=M)lc->inc(L,M);
        else rc->inc(M+1,R);
        up();
    }
    void dec(int L,int R){
        if(L==R){
            flag=(_and-_ans>_and);
            _and-=_ans;
            _or=_and;
            return;
        }
        int M=(L+R)>>1;
        dn();
        if(_l<=M)lc->dec(L,M);
        else rc->dec(M+1,R);
        up();
    }
    void inc1(int L,int R){
        if(flag)return;
        if(_l<=L){
            if(_and==~0u)return revs();
            if(L==R){
                _or=++_and;
                flag=1;
                return;
            }
        }
        dn();
        int M=(L+R)>>1;
        if(_l<=M)lc->inc1(L,M);
        rc->inc1(M+1,R);
        up();
    }
    void dec1(int L,int R){
        if(flag)return;
        if(_l<=L){
            if(_or==0u)return revs();
            if(L==R){
                _or=--_and;
                flag=1;
                return;
            }
        }
        dn();
        int M=(L+R)>>1;
        if(_l<=M)lc->dec1(L,M);
        rc->dec1(M+1,R);
        up();
    }
}ns[N*2],*np=ns,*rt;
node*build(int L,int R){
    node*w=np++;
    if(L<R){
        int M=(L+R)>>1;
        w->lc=build(L,M);
        w->rc=build(M+1,R);
    }
    w->_or=w->_and=w->rev=0;
    return w;
}
void inc(u32 a,int x){
    if(!a)return;
    _ans=a;_l=x;
    rt->inc(0,mx);
    if(flag){
        flag=0;
        _l=x+1;
        rt->inc1(0,mx);
    }
}
void dec(u32 a,int x){
    if(!a)return;
    _ans=a;_l=x;
    rt->dec(0,mx);
    if(flag){
        flag=0;
        _l=x+1;
        rt->dec1(0,mx);
    }
}
int main(){
    n=_();_();_();_();
    mx=n+10;
    if(mx<1000)mx=1000;
    rt=build(0,mx);
    for(int i=0;i<n;++i){
        if(_()==1){
            int a0=_(),b=_();
            int b1=b>>5,b2=b&31;
            if(a0>0){
                u32 a=a0;
                inc(a<<b2,b1);
                if(b2)inc(a>>(32-b2),b1+1);
            }else if(a0<0){
                u32 a=-a0;
                dec(a<<b2,b1);
                if(b2)dec(a>>(32-b2),b1+1);
            }
        }else{
            int k=_();
            _l=k>>5;
            rt->find(0,mx);
            printf("%d\n",_ans>>(k&31)&1);
        }
    }
    return 0;
}

d1t2

预处理询问涉及的串的hash值,用散列表离散化,对每次修改操作,枚举新产生/消失的长度<=50的子串,若其hash值等于某个询问,则对应在散列表上记录贡献。

#include<cstdio>
#include<cstring>
#include<vector>
typedef unsigned long long u64;
const int P=998244353,N=250007,Q=500007,pz=13999133,H=1<<25;
int _(){
    int x=0,f=1,c=getchar();
    while(c<48)c==‘-‘?f=-1:0,c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x*f;
}
int n,m,mk=1;
int v[N],nx[N],pv[N];
char ss[11000007];
u64 h1[11000007],pp[107];
int qs[Q][3];
std::vector<int>qv[Q];
u64 hx[H+777];
int hy[H+777];
int ins(u64 x){
    int w=(x^x>>25^x>>39)&(H-1);
    while(hx[w]){
        if(hx[w]==x)return w;
        w=(w+1237)&(H-1);
    }
    hx[w]=x;
    return w;
}
bool inc(u64 x,int a){
    int w=(x^x>>25^x>>39)&(H-1);
    while(hx[w]){
        if(hx[w]==x){
            hy[w]+=a;
            return 1;
        }
        w=(w+1237)&(H-1);
    }
    return 0;
}
int ls[111],lp,t0[11];
int ms[111],mp=0;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
void chk(int a,int b,int c){
    lp=mp=0;
    for(int i=1,w=a;i<mk&&w;++i,w=pv[w])ls[lp++]=v[w];
    for(int i=lp-1;i>=0;--i)ms[++mp]=ls[i];
    for(int i=1,w=b;i<mk&&w;++i,w=nx[w])ms[++mp]=v[w];
    for(int i=1;i<=mp;++i)h1[i]=h1[i-1]*pz+ms[i];
    for(int i=0;i<lp;++i){
        int r=min(mp,i+mk);
        for(int j=lp+1;j<=r;++j){
            inc(h1[j]-h1[i]*pp[j-i],c);
        }
    }
}
int main(){
    n=_();m=_();
    pp[0]=1;
    for(int i=1;i<=100;++i)pp[i]=pp[i-1]*pz;
    for(int i=1;i<=n;++i)++t0[v[i]=_()];
    for(int i=1;i<=m;++i){
        qs[i][0]=_();
        if(qs[i][0]==1){
            qs[i][1]=_();
            qs[i][2]=_();
        }else if(qs[i][0]==2){
            qs[i][1]=_();
        }else{
            scanf("%s",ss+1);
            int len=strlen(ss+1);
            int k=_();
            if(k>mk)mk=k;
            for(int j=1;j<=len;++j)h1[j]=h1[j-1]*pz+ss[j]-‘0‘;
            qv[i].resize(max(len-k+1,0));
            for(int j=k;j<=len;++j){
                qv[i][j-k]=ins(h1[j]-h1[j-k]*pp[k]);
            }
        }
    }
    for(int i=1;i<=6;++i)inc(i,t0[i]);
    for(int i=1;i<=m;++i){
        if(qs[i][0]==1){
            int a=qs[i][1],b=qs[i][2];
            nx[a]=b;pv[b]=a;
            chk(a,b,1);
        }else if(qs[i][0]==2){
            int a=qs[i][1],b=nx[a];
            nx[a]=pv[b]=0;
            chk(a,b,-1);
        }else if(qs[i][0]==3){
            int ans=1;
            for(int j=0;j<qv[i].size()&&ans;++j){
                ans=u64(ans)*hy[qv[i][j]]%P;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

d1t3

询问=k拆成<=k和<=k-1

只需考虑原矩形每一列最下面的一个可选位置,令f[x][y]表示最下方x行可选,第x+1行存在不可选位置,宽度y的矩形 合法的概率,则

$f[x][y]=\sum_{i=0}^{y-1}f[>=x][i]f[>x][y-1-i]$

这里dp不处理x=0的部分,只考虑x>0,因此0<xy<=k,暴力转移的时间复杂度可以接受

把0的影响表示为一个常系数线性齐次递推的形式,转化为多项式幂取模计算

#include<cstdio>
#include<cstring>
const int P=998244353;
typedef long long i64;
const i64 X=(1ll<<45)/P*P;
int pw(int a,int n){
    int v=1;
    for(;n;n>>=1,a=i64(a)*a%P)if(n&1)v=i64(v)*a%P;
    return v;
}
int n,m,q,A,B;
int f[1007][1007],g[1007][1007],cs[1007],v[1007],f0[1007],a0[1007],a1[1007];
i64 c[2007];
void mul(int*a,int*b,int m){
    memset(c,0,sizeof(c));
    for(int i=0;i<=m;++i){
        for(int j=0;j<=m;++j)c[i+j]+=i64(a[i])*b[j];
        if(i%8==7||i==m)for(int j=0;j<=m+i;++j)c[j]-=(c[j]>>45)*X;
    }
    for(int i=m*2;i>m;--i){
        c[i]%=P;
        for(int j=1;j<=m+1;++j)c[i-j]+=c[i]*v[j];
        if((m*2-i)%8==7)for(int j=0;j<i;++j)c[j]-=(c[j]>>45)*X;
    }
    for(int i=0;i<=m;++i)a[i]=c[i]%P;
}
int cal(int n,int m,int q){
    if(!m)return pw(1-q,n);
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    g[m+1][0]=1;
    cs[0]=1-q;
    for(int i=1;i<=m;++i)cs[i]=cs[i-1]*i64(q)%P;
    for(int i=m;i;--i){
        memcpy(g[i],g[i+1],sizeof(g[0]));
        for(int j=1;j<=m/i;++j){
            for(int k=0;k<j;++k){
                f[i][j]=(f[i][j]+i64(g[i][k])*g[i+1][j-1-k])%P;
            }
            f[i][j]=i64(cs[i])*f[i][j]%P;
            g[i][j]=(f[i][j]+g[i][j])%P;
        }
    }
    for(int i=1;i<=m+1;++i)v[i]=g[1][i-1]*i64(cs[0])%P;
    f0[0]=pw(cs[0],P-2);
    for(int i=1;i<=m+1;++i){
        f0[i]=0;
        for(int j=1;j<=i;++j)f0[i]=(f0[i]+f0[i-j]*i64(v[j]))%P;
    }
    memset(a0,0,sizeof(a0));
    memset(a1,0,sizeof(a1));
    a0[0]=a1[1]=1;
    for(;n;n>>=1,mul(a1,a1,m))if(n&1)mul(a0,a1,m);
    int s=0;
    for(int i=0;i<=m;++i)s=(s+i64(a0[i])*f0[i])%P;
    return s;
}
int main(){
    scanf("%d%d%d%d",&n,&m,&A,&B);
    ++n;
    q=i64(A)*pw(B,P-2)%P;
    int s=(cal(n,m,q)-cal(n,m-1,q))%P;
    printf("%d\n",(s+P)%P);
    return 0;
}

时间: 2024-12-23 18:27:51

noi2017 day1 题解的相关文章

NOI2014 Day1 题解。

自测100+100+62=262. BUAA给出的成绩是200,T3 checker评测windows选手答案都为RE. 起床困难综合征 sleep 题意:在[0,m]中取一个整数,使得n次给定的位运算操作后(包括and&,or|,xor^),答案最大.(m<=10^9,n<=10^5) 送分题.也许是NOI2013的金牌线偏低,DZD主席希望今年分数好看些. 二进制拆分. 先计算出每一位0/1经过n次位运算的答案. 再用数位DP求出答案最大值. 时间复杂度O(nlg^m). 1 #i

Noip 2016 Day1 题解

老师让我们刷历年真题, 然后漫不经心的说了一句:“你们就先做做noip2016 day1 吧” ...... 我还能说什么,,,,,老师你这是明摆着伤害我们啊2333333333 预计分数:100+25+24 实际分数:100+25+12 T1:玩具谜题 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外.如下图: 这时singer告诉小南一个谜題: “眼镜藏在我左数第3个玩具小

十连测Day1 题解

A. 奥义商店 有一个商店,n个物品,每个物品有一个价格和一种颜色. 有m个操作,操作有两种,一种是修改一个位置的价格,另一种是购买,每次购买指定一个公差d和一个位置k,找到包含这个位置k公差为d的同色最长等差数列,买下所有物品.让你给这个位置染成t种颜色中的一种(你来指定),其他位置会随机染成t种颜色之一,并保证这n-1个物品中第j种颜色的恰好有c[j]个.求最小期望花费保留四位小数. 注意询问相互独立,询问不会买走物品. 1<=n,m<=10^5,∑t<=2*10^5. 首先我们考虑

SDOI2017 Round1 Day1 题解 (BZOJ4816 BZOJ4817 BZOJ4818)

不知道有几个AK的,除了出题人SB搬了个BZOJ3779以外,应该没什么因素阻碍AK吧.要是SCOI考这套题多好. BZOJ4816 数字表格 SB反演,推出$ans=\prod_{i=1}^nf^{\sum_{j=1}^{\left\lfloor\frac ni\right\rfloor}\mu(j)\left\lfloor\frac n{ij}\right\rfloor\left\lfloor\frac m{ij}\right\rfloor}(i)$,直接$O(n^{\frac34}+n^{

AHOI2009最小割

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1072  Solved: 446[Submit][Status] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案,使中转站s不能到

1965: [Ahoi2005]SHUFFLE 洗牌

1965: [Ahoi2005]SHUFFLE 洗牌 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 408  Solved: 240[Submit][Status][Discuss] Description 为了表彰小联为Samuel星球的探险所做出的贡献,小联被邀请参加Samuel星球近距离载人探险活动. 由于Samuel星球相当遥远,科学家们要在飞船中度过相当长的一段时间,小联提议用扑克牌打发长途旅行中的无聊时间.玩了几局之后,大家觉得单纯玩扑克

2431: [HAOI2009]逆序对数列

2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 954  Solved: 548[Submit][Status] Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? Input 第一行为两个整数n,k. Output 写入一个整数,

BZOJ1875: [SDOI2009]HH去散步

1875: [SDOI2009]HH去散步 Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 620  Solved: 265[Submit][Status] Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法.

BZOJ1877: [SDOI2009]晨跑

1877: [SDOI2009]晨跑 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1024  Solved: 540[Submit][Status] Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交.E