NOI模拟15

开场看了一遍题,认为T1十分的有趣,于是进行了一个做,一直到10点的时候我还兴致勃勃的在玩Excel

直到搞到了70pts,开始头疼,疼死那种,完全无法思考,尝试喝水和去楼下溜达都不管事...

后面两个题直接弃掉了

T1 矩阵

考场上的是垃圾做法,完全是碰巧了找到了这个做法

先考虑只有一个对角线的时候,这时就是让ij不相等于是变成1,那么考虑推广

发现我们可以对列分奇偶性,这样的活只处理奇数或者偶数的话发现两行可以缩在一起,于是变回了上一个题,但是复杂度变为两倍

这个东西是可以继续推广的

考虑求不同的数如何做,一般来说是枚举二进制位哪个不同,这样的话是2log的,因为要交换10

但是我们有一个小trick,就是我们保证1的数目是相等的,这样就不用交换了,因为如果有一位这里是1那边是0,那么肯定还有一位是恰好相反的

这里用13位数6个1是正好的,离散化一下就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=3005;
int n,Q,ans;
int wo[N],ys[1<<13],cwo;
vector<int> cz[15][2],an[32][2];
signed main(){
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    n=read();Q=read();
    fo(i,1,(1<<13)-1)if(__builtin_popcount(i)==6)wo[++cwo]=i,ys[i]=cwo;
    fo(i,1,13){
        fo(j,1,cwo){
            if(wo[j]>>i-1&1)cz[i][1].push_back(j);
            else cz[i][0].push_back(j);
        }
        // cerr<<cz[i][0].size()<<" "<<cz[i][1].size()<<endl;
    }
    fo(i,1,13){
        ++ans;
        for(int x:cz[i][0]){
            if(x*2-1<=n)an[ans][0].push_back(x*2-1);
            if(x*2<=n)an[ans][0].push_back(x*2);
        }
        for(int x:cz[i][1]){
            if(x*2-1<=n)an[ans][1].push_back(x*2-1);
        }
        // cerr<<i<<" "<<cz[i][0][0]<<" "<<cz[i][1][0]<<endl;
        if(!an[ans][0].size()||!an[ans][1].size()){
            an[ans][0].clear();an[ans][1].clear();
            ans--;continue;
        }
    }
    fo(i,1,13){
        ++ans;an[ans][0].push_back(1);
        for(int x:cz[i][0]){
            if(x*2+1<=n)an[ans][0].push_back(x*2+1);
            if(x*2<=n)an[ans][0].push_back(x*2);
        }
        for(int x:cz[i][1]){
            if(x*2<=n)an[ans][1].push_back(x*2);
        }
        if(!an[ans][0].size()||!an[ans][1].size()){
            an[ans][0].clear();an[ans][1].clear();
            ans--;continue;
        }
    }
    printf("%d\n",ans);
    fo(i,1,ans){
        printf("%d %d ",(int)an[i][0].size(),(int)an[i][1].size());
        for(int x:an[i][0])printf("%d ",x);
        for(int x:an[i][1])printf("%d ",x);
        printf("\n");
    }
    return 0;
}

T2 字符串

好像这玩意就是个后缀树,不对,是垃圾版的后缀树

于是我们直接做个区间本质不同子串数就行了

这个东西用lct维护,扫描线,额去luogu看吧...

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=1e6+5;
int n,ans;char s[N];
struct Q{int l,r;}q[N<<1];
bool comQ(Q a,Q b){return a.r<b.r;}
struct SAM{
    struct POT{
        int son[2],fail;
        int len,pos;
    }tr[N<<1];
    int seg,las;
    SAM(){seg=las=1;}
    void ins(int c,int i){
        int np=++seg,p=las;las=np;
        tr[np].len=tr[p].len+1;tr[np].pos=i;
        while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
        if(!p)tr[np].fail=1;
        else {
            int q=tr[p].son[c];
            if(tr[q].len==tr[p].len+1)tr[np].fail=q;
            else {
                int nq=++seg;
                tr[nq]=tr[q];tr[nq].len=tr[p].len+1;
                tr[q].fail=tr[np].fail=nq;
                while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
            }
        }
    }
}sam;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int sm[N*4],tg[N*4];
    void pushup(int x){
        sm[x]=sm[ls]+sm[rs];
    }
    void pushdown(int x,int l,int r){
        int mid=l+r>>1;
        sm[ls]+=tg[x]*(mid-l+1);tg[ls]+=tg[x];
        sm[rs]+=tg[x]*(r-mid);tg[rs]+=tg[x];
        tg[x]=0;
    }
    void ins(int x,int l,int r,int ql,int qr,int v){
        if(ql>qr)return ;
        if(ql<=l&&r<=qr){
            sm[x]+=v*(r-l+1);
            tg[x]+=v;
            return ;
        }
        int mid=l+r>>1;if(tg[x])pushdown(x,l,r);
        if(ql<=mid)ins(ls,l,mid,ql,qr,v);
        if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
        pushup(x);
    }
    int qry(int x,int l,int r,int ql,int qr){
        if(ql>qr)return 0;
        if(ql<=l&&r<=qr)return sm[x];
        int mid=l+r>>1,ret=0;if(tg[x])pushdown(x,l,r);
        if(ql<=mid)ret+=qry(ls,l,mid,ql,qr);
        if(qr>mid)ret+=qry(rs,mid+1,r,ql,qr);
        return ret;
    }
    #undef ls
    #undef rs
}xds;
struct LCT{
    struct POT{
        int son[2],fa;
        int vl,tg;
    }tr[N<<1];
    void pushdown(int x){
        if(tr[x].tg){
            if(tr[x].son[0])tr[tr[x].son[0]].vl=tr[tr[x].son[0]].tg=tr[x].tg;
            if(tr[x].son[1])tr[tr[x].son[1]].vl=tr[tr[x].son[1]].tg=tr[x].tg;
            tr[x].tg=0;
        }
    }
    bool nroot(int x){return tr[tr[x].fa].son[0]==x||tr[tr[x].fa].son[1]==x;}
    bool get(int x){return tr[tr[x].fa].son[1]==x;}
    void rotate(int x){
        int y=tr[x].fa,z=tr[y].fa;
        int xpos=get(x),ypos=get(y);
        if(nroot(y))tr[z].son[ypos]=x;
        tr[x].fa=z;tr[y].fa=x;
        tr[y].son[xpos]=tr[x].son[xpos^1];
        tr[x].son[xpos^1]=y;
        tr[tr[y].son[xpos]].fa=y;
    }
    int pth[N<<1],pt;
    void splay(int x){
        int now=x;pth[++pt]=x;
        while(nroot(now))pth[++pt]=now=tr[now].fa;
        while(pt)pushdown(pth[pt--]);
        while(nroot(x)){
            int y=tr[x].fa;
            int xpos=get(x),ypos=get(y);
            if(nroot(y)){
                if(xpos==ypos)rotate(y);
                else rotate(x);
            }rotate(x);
        }
    }
    void access(int x,int v){
        for(int y=0;x;y=x,x=tr[x].fa){
            splay(x);tr[x].son[1]=y;
            if(tr[x].vl)xds.ins(1,1,n,tr[x].vl-sam.tr[x].len+1,tr[x].vl-sam.tr[tr[x].fa].len,-1);
            tr[x].vl=tr[x].tg=v;
        }
        xds.ins(1,1,n,1,v,1);
    }
}lct;
int pos[N];
signed main(){
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    scanf("%s",s+1);n=strlen(s+1);reverse(s+1,s+n+1);
    fo(i,1,n)sam.ins(s[i]-'0',i),pos[i]=sam.las;
    fo(i,2,sam.seg){
        q[i]=Q{sam.tr[i].pos-sam.tr[i].len+1,sam.tr[i].pos-sam.tr[sam.tr[i].fail].len};
        lct.tr[i].fa=sam.tr[i].fail;
    }
    sort(q+2,q+sam.seg+1,comQ);int now=1;
    fo(i,2,sam.seg){
        while(now<=q[i].r)lct.access(pos[now],now),now++;
        ans+=xds.qry(1,1,n,q[i].l,q[i].r);
        // cerr<<ans<<" "<<q[i].l<<" "<<q[i].r<<" "<<xds.qry(1,1,n,q[i].l,q[i].r)<<endl;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2022-06-08 14:32  fengwu2005  阅读(29)  评论(0编辑  收藏  举报