zoukankan      html  css  js  c++  java
  • 做题记录

    UOJ 176 新年的繁荣

    一个奇特的想法。我们考虑从大到小枚举边权,显然每次合并的话只用考虑比当前枚举的i多一位的数 因为如果两个数有其它的重叠部分 就一定会在之前被合并掉了

    复杂度:$O(2^m*alpha(n))$

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define inf 20021225
    #define N 1<<18
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')    f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')    s=s*10+ch-'0',ch=getchar();
        return s*f;
    }
    int f[N];
    int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    int main()
    {
        int n=read(),m=read(),x; ll ans=0;
        for(int i=1;i<=n;i++)
        {
            x=read(); if(f[x])    ans+=x; else f[x]=x;
        }
        int top=1<<m; top--;
        for(int i=top;i;i--)
        {
            int tmp=f[i];
            for(int j=0,ff;j<m;j++)
            {
                if(i&(1<<j))    continue;
                if(tmp)
                {
                    if(f[i|(1<<j)] && (ff=find(f[i|(1<<j)]))!=tmp)
                        ans+=i,f[ff]=tmp;
                }
                else if(f[i|(1<<j)])    tmp=find(f[i|(1<<j)]);
            }
            f[i]=tmp;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    UOJ176

    UOJ 308 UOJ拯救计划

    看到%6应该就有些想法了 我们考虑只做%2 和 %3的答案 原来的柿子长这样

    $ans=sum A(k,i)*[用i个颜色染色的方案数]$

    所以当i>=3的时候一定是满足%3%2=0的 于是我们只需要考虑用1/2种颜色染色的方案数 简单dp即可

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define inf 20021225
    #define N 100010
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')    f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')    s=s*10+ch-'0',ch=getchar();
        return s*f;
    }
    struct node{int to,lt;}e[N<<2];
    int n,k,m; int vis[N],in[N],cnt;
    void add(int x,int y)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt;
    }
    bool check(int x,bool f)
    {
        for(int i=in[x];i;i=e[i].lt)
        {
            int to=e[i].to;
            if(vis[to]==vis[x])    f|=1;
            else if(vis[to]==-1)
                vis[to]=vis[x]^1,f|=check(to,f);
        }
        return f;
    }
    int main()
    {
        int T=read(),x,y,ans2,ans3;
        while(T--)
        {
            memset(in,0,sizeof(in));
            memset(vis,-1,sizeof(vis));
            cnt=0;
            n=read(),m=read();
            for(int i=1;i<=m;i++)
                x=read(),y=read(),add(x,y);
            ans2=!m,ans3=1;
            for(int i=1;i<=n;i++)    ans3=(ans3<<1)%3;
            for(int i=1;i<=n;i++)
                if(vis[i]==-1)
                {
                    vis[i]=1; bool f=check(i,0);
                    if(!f)    ans3=(ans3<<1)%3;
                    else{ans3=0; break;}
                }
            if(ans2)
            {
                if(!ans3)    printf("3
    ");
                else if(ans3==1)    printf("1
    ");
                else printf("5
    ");
            }
            else
            {
                if(!ans3)    printf("0
    ");
                else if(ans3==1)    printf("4
    ");
                else    printf("2
    ");
            }
        }
        return 0;
    }
    UOJ308

    BJOI 连连看

    我们观(luan)察(gao)发现这其实是一个二分图 所以直接费用流就可以了

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #define ll long long
    #define inf 20021225
    #define N 1010
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')    f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9')    s=s*10+ch-'0',ch=getchar();
        return s*f;
    }
    struct edge{int to,lt,f,c,fr;}e[N*100];
    int in[N],cnt=1,s,t,dep[N]; bool vis[N];
    queue<int> que; int lst[N];
    void add(int x,int y,int f,int c)
    {
        e[++cnt].to=y; e[cnt].fr=x; e[cnt].lt=in[x]; e[cnt].f=f; e[cnt].c=c; in[x]=cnt;
        e[++cnt].to=x; e[cnt].fr=y; e[cnt].lt=in[y]; e[cnt].f=0; e[cnt].c=-c; in[y]=cnt;
    }
    bool spfa()
    {
        while(!que.empty())    que.pop();
        memset(dep,-48,sizeof(dep));
        memset(vis,0,sizeof(vis));
        vis[s]=1; dep[s]=0; que.push(s);
        while(!que.empty())
        {
            int x=que.front(); que.pop(); vis[x]=0;
            for(int i=in[x];i;i=e[i].lt)
            {
                int y=e[i].to;
                if(e[i].f&&dep[y]<dep[x]+e[i].c)
                {
                    dep[y]=dep[x]+e[i].c; lst[y]=i;
                    if(!vis[y])    vis[y]=1,que.push(y);
                }
            }
        }
        return dep[t]>dep[0];
    }
    void dinic()
    {
        int cost=0,par=0;
        while(spfa())
        {
            int flow=inf;
            for(int i=lst[t];i;i=lst[e[i].fr])    flow=min(flow,e[i].f);
            for(int i=lst[t];i;i=lst[e[i].fr])
                cost+=flow*e[i].c,e[i].f-=flow,e[i^1].f+=flow;
            par+=flow;
        }
        printf("%d %d
    ",par,cost);
    }
    int col[N],a,b;
    int gcd(int x,int y){return y?gcd(y,x%y):x;}
    vector<int> edg[N];
    #define pb push_back
    void dfs(int x)
    {
        for(int i=0;i<edg[x].size();i++)
            if(col[edg[x][i]]==-1)
                col[edg[x][i]]=col[x]^1,dfs(edg[x][i]);
    }
    int main()
    {
        a=read(),b=read();
        for(int i=a;i<=b;i++)    for(int j=i+1;j<=b;j++)
        {
            int w=j*j-i*i; int d=sqrt(w);
            if(d*d==w && gcd(i,d)==1)
                edg[i].pb(j),edg[j].pb(i);
        }
        memset(col,-1,sizeof(col)); s=N-3; t=s+1;
        for(int i=a;i<=b;i++)    if(col[i]==-1)
            col[i]=0,dfs(i);
        for(int i=a;i<=b;i++)
        {
            if(col[i])
                add(i,t,1,0);
            else
            {
                add(s,i,1,0);
                for(int j=0;j<edg[i].size();j++)
                    add(i,edg[i][j],1,i+edg[i][j]);
            }
        }
        dinic();
        return 0;
    }
    连连看

    BZOJ4231 回忆树

    一道全部由NOIp内容组成的好题(逃

    我们发现这个答案显然具有差分性 所以我们可以对于每个点求答案然后链上差分掉 具体实现就是树状数组 还剩一种情况就是模式串跨LCA 这样的长度不超过两倍的模式串长度 所以我们把它提出来做KMP就好啦 (就写的很开心

    //Love and Freedom.
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #include<vector>
    #define LG 19
    #define ll long long
    #define inf 20021225
    #define N 500001
    #define lowbit(x) (x&-x)
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0' || ch>'9')    {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0' && ch<='9')    s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct Edge{int to,lt;}e[N<<1]; int in[N],cnt;
    struct node{int fail,son[26];};
    struct edge{int to,lt; char c;}a[N<<1];
    int ia[N],ant,n,m;
    int dfn[N][2],tm;
    void add(int x,int y,char c)
    {
        a[++ant].to=y; a[ant].lt=ia[x]; a[ant].c=c; ia[x]=ant;
        a[++ant].to=x; a[ant].lt=ia[y]; a[ant].c=c; ia[y]=ant;
    }
    void add(int x,int y)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt;
    }
    void dfs(int x)
    {
        dfn[x][0]=++tm;
        for(int i=in[x];i;i=e[i].lt)    dfs(e[i].to);
        dfn[x][1]=tm;
    }
    struct BIT
    {
        int n,a[N];
        void add(int x,int y){x=dfn[x][0]; while(x<=n)    a[x]+=y,x+=lowbit(x);}
        int qry(int x){int ans=0; while(x)    ans+=a[x],x-=lowbit(x); return ans;}
        int ask(int x){return qry(dfn[x][1])-qry(dfn[x][0]-1);}
    };
    struct ACA
    {
        node t[N]; int rt,poi; queue<int> q;
        int id(char c){return c-'a';}
        void init(){rt=poi=0;}
        int insert(char *ch)
        {
            int n=strlen(ch),pos=rt;
            for(int i=0,d=id(ch[i]);i<n;i++,d=id(ch[i]))
            {
                if(!t[pos].son[d])    t[pos].son[d]=++poi;
                pos=t[pos].son[d];
            }
            return pos;
        }
        void getfail()
        {
            for(int i=0;i<26;i++)    if(t[rt].son[i])
                q.push(t[rt].son[i]);
            while(!q.empty())
            {
                int x=q.front(); q.pop();
                for(int i=0;i<26;i++)
                    if(t[x].son[i])
                        t[t[x].son[i]].fail=t[t[x].fail].son[i],q.push(t[x].son[i]);
                    else
                        t[x].son[i]=t[t[x].fail].son[i];
            }
            for(int i=1;i<=poi;i++)    add(t[i].fail,i);
            dfs(rt);
            //for(int i=1;i<=poi;i++)    printf("%d
    ",dfn[i][0]);
        }
    }A;
    BIT tr; int f[N][LG],dep[N]; char cf[N];
    void getfa(int x,int fa)
    {
        dep[x]=dep[fa]+1; f[x][0]=fa;// cf[x]=0;
        for(int i=1;i<LG;i++)    f[x][i]=f[f[x][i-1]][i-1];
        for(int i=ia[x];i;i=a[i].lt)
        {
            int y=a[i].to; if(y==fa)    continue;
            getfa(y,x); cf[y]=a[i].c;
        }
    }
    int jump(int x,int len)
    {
        for(int i=0;i<LG;i++)    if((len>>i)&1)
            x=f[x][i];
        return x;
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])    swap(x,y);
        x=jump(x,dep[x]-dep[y]);// printf("%d %d
    ",x,y);
        if(x==y)    return x;
        for(int i=LG-1;~i;i--)    if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    int nxt[N];
    int kmp(char *s,char *t)
    {
        int sn=strlen(s),tn=strlen(t);
        for(int i=1;i<=tn;i++)
        {
            int j=nxt[i];
            while(j&&t[i]!=t[j])    j=nxt[j];
            if(t[j]==t[i])    nxt[i+1]=j+1;
            else    nxt[i+1]=0;
        }
        int ans=0;
        for(int j=0,i=0;i<sn;i++)
        {
            while(j&&t[j]!=s[i])    j=nxt[j];
            if(t[j]==s[i])    j++;
            if(j==tn)    ans++;
        }
        return ans;
    }
    #define pa pair<int,int>
    #define mp make_pair
    #define fs first
    #define se second
    vector<pa> pq[N];
    int ans[N];
    void DFS(int x,int y)
    {
        //printf("%d %d
    ",x,y);
        tr.add(y,1);// printf("%d
    ",y);
        for(int i=0;i<pq[x].size();i++)
        {
            pa o=pq[x][i];// printf("%d %d %d %d %d
    ",y,x,o.fs,o.se,tr.ask(o.se));
            if(o.fs>0)    ans[o.fs]+=tr.ask(o.se);
            else    ans[-o.fs]-=tr.ask(o.se);
        }
        for(int i=ia[x];i;i=a[i].lt)    if(a[i].to!=f[x][0])
            DFS(a[i].to,A.t[y].son[a[i].c-'a']);
        tr.add(y,-1);
    }
    char tmp[N];
    int cross(int x,int y,char *s)
    {
        int sn=strlen(s); int lca=LCA(x,y);
        int dx=min(dep[x],dep[lca]+sn-1);
        x=jump(x,dep[x]-dx);
        int dy=min(dep[y],dep[lca]+sn-1);
        y=jump(y,dep[y]-dy);
        int cnt=0;
        for(;x!=lca;x=f[x][0])    tmp[cnt++]=cf[x];
        int remcnt=cnt;
        for(;y!=lca;y=f[y][0])    tmp[cnt++]=cf[y];
        reverse(tmp+remcnt,tmp+cnt); tmp[cnt]=0;
        return kmp(tmp,s);
    }
    char ch[N];
    int main()
    {
        n=read(),m=read(); int x,y; char c;
        for(int i=1;i<n;i++)
            x=read(),y=read(),c=getchar(),add(x,y,c);
        getfa(1,0);
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(); scanf("%s",ch); int len=strlen(ch);
            ans[i]=cross(x,y,ch); int lca=LCA(x,y),pos;// printf("%d
    ",ans[i]);
            if(dep[y]-dep[lca]>=len)
                pos=A.insert(ch),pq[y].push_back(mp(i,pos)),pq[jump(y,dep[y]-dep[lca]-len+1)].push_back(mp(-i,pos));
            reverse(ch,ch+len);
            if(dep[x]-dep[lca]>=len)
                pos=A.insert(ch),pq[x].push_back(mp(i,pos)),pq[jump(x,dep[x]-dep[lca]-len+1)].push_back(mp(-i,pos)); 
        }
        A.getfail();// printf("QAQ");
        tr.n=tm; DFS(1,0);
        for(int i=1;i<=m;i++)    printf("%d
    ",ans[i]);
        return 0;
    }
    BZOJ4231

    CF Gym 102129 I Incomparable Pairs

    大火题(雾 把问题转化成区间本质不同子串对数 然后后缀自动机和线段树维护即可 后缀自动机维护的时候其实用到了SDOI树点染色的思想 用LCT维护结构 Access来保证复杂度 然后就是写起来很爽而已

    //Love and Freedom.
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #define N 400010
    #define ll long long
    #define inf 20021225
    #define id(x) (x-'a')
    #define ll __int128
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0' || ch>'9')    {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0' && ch<='9')    s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    #define ls (x<<1)
    #define rs (x<<1|1)
    struct SGT
    {
        ll a[N<<2],tag[N<<2],a2[N<<2];
        void put(int x,int l,int r,ll v)
        {
            tag[x]+=v; a[x]+=(r-l+1)*v;
            a2[x]+=v*(r-l+1)*(r+l)/2;
        }
        void pushdown(int x,int l,int r)
        {
            if(!tag[x])    return;
            int mid=l+r>>1,t=tag[x]; tag[x]=0;
            put(ls,l,mid,t); put(rs,mid+1,r,t);
        }
        void pushup(int x){a[x]=a[ls]+a[rs]; a2[x]=a2[ls]+a2[rs];}
        void modify(int x,int l,int r,int LL,int RR,ll v)
        {
            if(LL<=l&&RR>=r){put(x,l,r,v); return;}
            int mid=l+r>>1; pushdown(x,l,r);
            if(LL<=mid)    modify(ls,l,mid,LL,RR,v);
            if(RR>mid)    modify(rs,mid+1,r,LL,RR,v);
            pushup(x);
        }
        ll query(int x,int l,int r,int LL,int RR)
        {
            if(LL<=l&&RR>=r)    return a[x];
            int mid=l+r>>1; pushdown(x,l,r); ll ans=0;
            if(LL<=mid)    ans+=query(ls,l,mid,LL,RR);
            if(RR>mid)    ans+=query(rs,mid+1,r,LL,RR);
            pushup(x); return ans;
        }
        ll query2(int x,int l,int r,int LL,int RR)
        {
            if(LL<=l&&RR>=r)    return a2[x];
            int mid=l+r>>1; pushdown(x,l,r); ll ans=0;
            if(LL<=mid)    ans+=query2(ls,l,mid,LL,RR);
            if(RR>mid)    ans+=query2(rs,mid+1,r,LL,RR);
            return ans;
        }
    }T;
    #undef ls
    #undef rs
    #define ls(x) t[x].son[0]
    #define rs(x) t[x].son[1]
    #define nrt(x) (t[t[x].fa].son[0]==x || t[t[x].fa].son[1]==x)
    struct sam{int son[26],fa,len;}s[N];
    struct lct{int son[2],fa,val,tag;}t[N];
    int lt,poi,rt,pos[N],ful[N];
    char ch[N]; int n,top;
    void init(){pos[0]=lt=poi=rt=1;}
    void insert(int id,int c)
    {
        int p=lt,np=lt=++poi; pos[id]=np;
        s[np].len=s[p].len+1; ful[np]=id;
        for(;p&&!s[p].son[c];p=s[p].fa)    s[p].son[c]=np;
        if(!p){s[np].fa=rt; return;} int q=s[p].son[c];
        if(s[q].len==s[p].len+1){s[np].fa=q; return;}
        int nq=++poi; s[nq].len=s[p].len+1;
        memcpy(s[nq].son,s[q].son,sizeof(s[q].son));
        s[nq].fa=s[q].fa; s[q].fa=s[np].fa=nq;
        for(;p&&s[p].son[c]==q;p=s[p].fa)    s[p].son[c]=nq;
    }
    void mark(int x,int v)
    {
        t[x].tag=t[x].val=v;
    }
    void pushdown(int x)
    {
        if(!t[x].tag)    return;
        int tx=t[x].tag; t[x].tag=0;
        if(ls(x))    t[ls(x)].val=t[ls(x)].tag=tx;
        if(rs(x))    t[rs(x)].val=t[rs(x)].tag=tx;
    }
    void push(int x){if(nrt(x))    push(t[x].fa); pushdown(x);}
    void rotate(int x)
    {
        if(!x || !nrt(x))    return;
        int f=t[x].fa,gf=t[f].fa;
        int p=rs(f)==x,k=p^1;
        if(nrt(f))    t[gf].son[rs(gf)==f]=x;
        t[x].fa=gf; t[f].fa=x;
        if(t[x].son[k])    t[t[x].son[k]].fa=f;
        t[f].son[p]=t[x].son[k]; t[x].son[k]=f;
    }
    void splay(int x)
    {
        if(!x)    return; push(x);
        while(nrt(x))
        {
            int f=t[x].fa,gf=t[f].fa;
            if(nrt(f))    (rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f);
            rotate(x);
        }
    }
    #define pa pair<int,int>
    #define mp make_pair
    #define fs first
    #define se second
    #define pb push_back
    pa seq[N]; vector<pa> qry[N];
    void modify(int l,int r,ll v){T.modify(1,1,n,l,r,v);}
    void access(int x,int val)
    {
        int y=0; top=0;
        while(x)
        {
            splay(x); top++;
            //printf("%d %d
    ",s[x].len,t[x].val);
            seq[top]=mp(s[x].len,t[x].val);
            t[x].son[1]=y; mark(x,val);
            y=x; x=t[x].fa;
        }
        //t[x].val=val;
    }
    vector<int> e[N];
    void add(int x,int y)
    {
        e[x].pb(y);
    }
    void dfs(int x)
    {
        for(int i=0;i<e[x].size();i++)
            dfs(e[x][i]),ful[x]=ful[e[x][i]];
    }
    void build()
    {
        init();
        for(int i=1;i<=n;i++)    insert(i,id(ch[i]));
        for(int i=2;i<=poi;i++)    add(s[i].fa,i);
    }
    void solve()
    {
        ll ans=0; build(); dfs(1);
        for(int i=2;i<=poi;i++)
            //printf("%d ",ful[i]),
            qry[ful[i]].push_back(mp(ful[i]-s[i].len+1,ful[i]-s[s[i].fa].len));
        for(int i=1;i<=poi;i++)    t[i].fa=s[i].fa;
        for(int i=1;i<=n;i++)
        {
            modify(1,i,1);
            access(pos[i],i);
            //printf("%d %d
    ",pos[i],i);
            int lst=0;
            for(int j=top;j>1;j--)
            {
                pa tmp=seq[j];
                //printf("%d %d
    ",tmp.fs,tmp.se);
                if(tmp.fs)
                {
                    if(tmp.se)    modify(tmp.se-tmp.fs+1,tmp.se-lst,-1);
                    lst=tmp.fs;
                }
            }
            for(int j=0;j<qry[i].size();j++)
            {
                pa tmp=qry[i][j];// printf("%d %d
    ",tmp.fs,tmp.se);
                ans+=T.query2(1,1,n,tmp.fs,tmp.se);
                //printf("%lld
    ",T.query2(1,1,n,tmp.fs,tmp.se));
                ans-=T.query(1,1,n,tmp.fs,tmp.se)*(tmp.fs-1);
                if(tmp.se!=i)
                    ans+=T.query(1,1,n,tmp.se+1,i)*(tmp.se-tmp.fs+1);
            }
            //printf("%lld ",ans);
        }
        ll sum=0;
        for(int i=2;i<=poi;i++)    sum+=s[i].len-s[s[i].fa].len;
        sum=sum*(sum+1)/2;// printf("%d
    ",ans);
        printf("%llu
    ",(unsigned long long)sum-ans);
    }
    int main()
    {
        scanf("%s",ch+1); n=strlen(ch+1);
        solve();
        return 0;
    }
    Incomparable Pairs

    SCOI2016 萌萌哒

    用ST表来表示区间 然后并查集合并看做标记 最后统计答案的时候把ST表上的标记全部下传 没想到并查集还可以这么用系列

    //Love and Freedom.
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    #define inf 20021225
    #define N 100010
    #define LG 19
    #define mdn 1000000007
    #define inv 700000005
    using namespace std;
    int read()
    {
        int s=0; char ch=getchar();
        while(ch<'0'||ch>'9')    ch=getchar();
        while(ch<='9'&&ch>='0')    s=s*10+ch-'0',ch=getchar();
        return s;
    }
    int f[N*LG],id[N][LG],pos[N*LG],tot;
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    void merge(int x,int y){f[find(x)]=find(y);}
    void pushdown(int x,int l)
    {
        int tmp=find(id[x][l]);
        if(tmp==id[x][l])    return;
        int y=pos[tmp];
        merge(id[x][l-1],id[y][l-1]);
        merge(id[x+(1<<l-1)][l-1],id[y+(1<<l-1)][l-1]);
    }
    int main()
    {
        int n=read(),m=read();
        for(int i=0;i<LG;i++)    for(int j=1;j+(1<<i)-1<=n;j++)
            id[j][i]=++tot,pos[tot]=j,f[tot]=tot;
        while(m--)
        {
            int l1=read(),r1=read(),l2=read(),r2=read();
            int len=r1-l1+1;
            for(int i=0;i<LG;i++)    if(len&(1<<i))
                merge(id[l1][i],id[l2][i]),l1+=1<<i,l2+=1<<i;
        }
        for(int i=LG-1;i;i--)    for(int j=1;j+(1<<i)-1<=n;j++)
            pushdown(j,i);
        int ans=1;
        for(int i=1;i<=n;i++)    if(find(f[id[i][0]])==id[i][0])    ans=1ll*ans*10%mdn;
        ans=1ll*ans*inv%mdn*9%mdn; printf("%d
    ",ans);
        return 0;
    }
    萌萌哒

    好像还有很多校内题不方便放 那先这样吧qaq

    CF GYM 102268 D Dates

    为什么这个题出到Noip模拟赛啊(

    我们先考虑暴力做法,我们需要一个有正确性的算法进行优化。首先可以想到我们把所有区间按照权值大小从大到小排序,然后每次加入一个看是否仍存在完备匹配。

    考虑优化,完备匹配显然可以通过Hall定理来优化。

    Hall定理:二分图存在完备匹配必须有X中的任意k个点至少与Y中的k个点相邻。

    貌似之前觉得这玩意很没用

    也就是说我们现在要考虑对于任意L,R都有$sum_{i=L}^R a_i >= sum_{i=1}^n b_i[l_i>=L][r_i<=R]$ 其中$b_i$表示是否选择i号的0/1变量

    由于题目给定了$l_i<=l_{i+1} r_i<=r_{i+1}$所以我们可以把枚举L,R变成枚举数组下标LL,RR 也就是说我们现在要判断的是$sum_{i=l_{LL}^{r_{RR}}} a_i >= sum_{i={LL}}^{RR} b_i$

    我们改写成前缀和形式也就是$sa_{r_{RR}} - sa_{l_{LL}} >= sb_{RR} - sb_{LL}$ 继续移项得到 $sb_{LL} - sa_{l_{LL}} >= sb_{RR} - sa_{r_{RR}}$

    我们考虑把一个$b_i=0$改为$b_i=1$ 我们只需要考虑 前缀的最小值(左式)是否大于后缀的最大值(右式)【其实也就代表了所有区间】即可 所以我们用两棵线段树来分别维护这个操作即可。

    总结一下:1.想到贪心完备匹配解法。2.考虑到Hall定理。3.通过画柿子得到可以维护的东西。这里面还用到的东西还有任意左端点和任意右端点来代表任意区间。前缀和优化。等等。

    好神仙啊。(NOIP打死也不会出这种东西吧

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define inf 2002122519980707ll
    #define N 300100
    #define ls x<<1
    #define rs x<<1|1
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct sgt
    {
        int typ; ll f[N<<2],tag[N<<2];
        ll upd(ll x,ll y){return typ?max(x,y):min(x,y);}
        void put(int x,ll v){tag[x]+=v; f[x]+=v;}
        void pushdown(int x)
        {
            if(!tag[x])    return;
            put(ls,tag[x]); put(rs,tag[x]); tag[x]=0;
        }
        void build(ll *a,int x,int l,int r)
        {
            if(l==r){f[x]=a[l]; return;} int mid=l+r>>1;
            build(a,ls,l,mid); build(a,rs,mid+1,r); f[x]=upd(f[ls],f[rs]);
        }
        void modify(int x,int l,int r,int LL,int RR,int v)
        {
            if(l>=LL&&r<=RR){put(x,v); return;}
            int mid=l+r>>1; pushdown(x);
            if(LL<=mid)    modify(ls,l,mid,LL,RR,v);
            if(RR>mid)    modify(rs,mid+1,r,LL,RR,v);
            f[x]=upd(f[ls],f[rs]);
        }
        ll query(int x,int l,int r,int LL,int RR)
        {
            if(l>=LL&&r<=RR)    return f[x];
            int mid=l+r>>1; ll ans=typ?-inf:inf; pushdown(x);
            if(LL<=mid)    ans=upd(ans,query(ls,l,mid,LL,RR));
            if(RR>mid)    ans=upd(ans,query(rs,mid+1,r,LL,RR));
            return ans;
        }
    }t[2];
    ll pre[N]; int n,T; ll t0[N],t1[N];
    struct node{int l,r,v,id;}a[N];
    bool operator<(node x,node y){return x.v>y.v;}
    int main()
    {
        n=read(); T=read(); t[0].typ=1;
        for(int i=1;i<=T;i++)    pre[i]=read(),pre[i]+=pre[i-1];
        for(int i=1;i<=n;i++)
            a[i].l=read(),a[i].r=read(),a[i].v=read(),
            t0[i]=-pre[a[i].r],t1[i]=-pre[a[i].l-1],a[i].id=i;
        sort(a+1,a+n+1); ll ans=0; t[0].build(t0,1,1,n); t[1].build(t1,1,1,n);
        for(int i=1;i<=n;i++)
        {
            if(t[0].query(1,1,n,a[i].id,n)>=t[1].query(1,1,n,1,a[i].id))    continue;
            ans+=a[i].v; t[0].modify(1,1,n,a[i].id,n,1);
            if(a[i].id<n)    t[1].modify(1,1,n,a[i].id+1,n,1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    CF GYM 102268 D

    AGC037D Sorting a Grid

    很科学的东西。。。考虑倒着推,每个数编号$lfloor frac{a_{i,j}-1}{n} floor+1$也就是1-m然后b数组一定是每一列都是一个1-m的排列 显然用二分图匹配做一个行和数字的匹配即可,每做完一边删掉一列就可以了qwq。

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #define ll long long
    #define inf 20021225
    #define N 210
    #define M 20001
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct edge{int to,lt,f;}e[M];
    int in[N],cnt,s,t,n,m; // clear!
    void add(int x,int y,int f)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; e[cnt].f=f;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; e[cnt].f=0;
    }
    queue<int> que; int dep[N];
    bool bfs()
    {
        //printf("GG");
        while(!que.empty())    que.pop();
        memset(dep,0,sizeof(dep)); que.push(s); dep[s]=1;
        while(!que.empty())
        {
            int x=que.front(); que.pop();
            for(int i=in[x];i;i=e[i].lt)    if(!dep[e[i].to] && e[i].f)
            {
                dep[e[i].to]=dep[x]+1,que.push(e[i].to);
                if(e[i].to==t)    return 1;
            }
        }
        return 0;
    }
    int dfs(int x,int flow)
    {
        if(x==t)    return flow;
        int cur=flow;
        for(int i=in[x];i;i=e[i].lt)
        {
            int y=e[i].to; if(dep[y]==dep[x]+1 && e[i].f)
            {
                int tmp=dfs(y,min(cur,e[i].f));// printf("GG");
                cur-=tmp; e[i].f-=tmp; e[i^1].f+=tmp;
                if(!cur)    return flow;
            }
        }
        dep[x]=-1; return flow-cur;
    }
    vector<int> val[N][N]; int sz[N][N];
    void link()
    {
        cnt=1; s=N-3; t=s+1;
        memset(in,0,sizeof(in));
        for(int i=1;i<=n;i++)
        {
            add(s,i,1);
            for(int j=1;j<=n;j++)
                if(sz[i][j]<val[i][j].size())    add(i,n+j,1);
        }
        for(int i=1;i<=n;i++)    add(n+i,t,1);
    }
    int r[N],b[N][N],a[N][N];
    void dinic()
    {
        //printf("QAQ");
        while(bfs())    dfs(s,inf);
        //printf("QwQ");
        for(int i=1;i<=n;i++)
            for(int j=in[i];j;j=e[j].lt)
            {
                if(e[j].to!=s && e[j^1].f)
                {
                    r[i]=e[j].to-n;// printf("%d %d
    ",i,r[i]);
                    break;
                }
            }
        //printf("QAQ");
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)
        {
            a[i][j]=read(); int id=(a[i][j]-1)/m+1; val[i][id].push_back(a[i][j]);
            //printf("%d %d
    ",i,id);
        }
        //printf("OVO");
        for(int i=1;i<=m;i++)
        {
            link(); dinic();// printf("GG");
            for(int j=1;j<=n;j++)    b[j][i]=val[j][r[j]][sz[j][r[j]]++];
            //printf("QAQ");
        }
        for(int i=1;i<=n;i++,printf("
    "))    for(int j=1;j<=m;j++)
            printf("%d ",b[i][j]),a[j][i]=b[i][j];
        for(int i=1;i<=m;i++)    sort(a[i]+1,a[i]+n+1);
        for(int i=1;i<=n;i++,printf("
    "))    for(int j=1;j<=m;j++)
            printf("%d ",a[j][i]);
        return 0;
    }
    AGC037D

    Atcoder JSC2019 F Candy Retribution

    画柿子好题,主要是第一步想到容斥做m和m+1不同的。然后接下来再套一步容斥,考虑有几个<m的就可以了。然后复杂度分析用到调和级数。

    用到一个小trick就是1~m个球插板n个筐的答案是C(m,n) 可以考虑组合意义 也可以考虑直接画柿子$sum_{i=0}^{m} C(i,n-1) = C(m,n)$(杨辉三角上的一列)

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define inf 20021225
    #define N 600010
    #define mdn 1000000007
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    int fac[N],inv[N];
    int ksm(int bs,int mi)
    {
        int ans=1;
        while(mi)
        {
            if(mi&1)    ans=1ll*ans*bs%mdn;
            bs=1ll*bs*bs%mdn; mi>>=1;
        }
        return ans;
    }
    void init(int n)
    {
        fac[0]=1;
        for(int i=1;i<=n;i++)    fac[i]=1ll*fac[i-1]*i%mdn;
        inv[n]=ksm(fac[n],mdn-2);
        for(int i=n;i;i--)    inv[i-1]=1ll*inv[i]*i%mdn;
    }
    int C(int n,int m)
    {
        if(n<m)    return 0;
        return 1ll*fac[n]*inv[n-m]%mdn*inv[m]%mdn;
    }
    void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
    void dpu(int &x,int y){x-=x-y<0?y-mdn:y;}
    int n,m;
    int get(int s,int p)
    {
        if(s<0)    return 0; int ans=0;
        for(int i=0;i*p<=s && i<=n-m;i++)
        {
            int tmp=1ll*C(n-m,i)*C(s-i*p+n,n)%mdn;
            if(i&1)    dpu(ans,tmp); else upd(ans,tmp);
        }
        return 1ll*C(n,m)*ans%mdn;
    }
    int solve(int s,int n)
    {
        int ans=C(s+n,n);
        for(int i=1;i*m<=s;i++)
            dpu(ans,(get(s-i*m,i)-get(s-(i+1)*m,i)+mdn)%mdn);
        return ans;
    }
    int main()
    {
        n=read(),m=read(); int l=read(),r=read(); init(n+r);
        printf("%d
    ",(solve(r,n)-solve(l-1,n)+mdn)%mdn);
        return 0;
    }
    Candy Retribution

    AGC013C Ants on a Circle

    口胡的一道题,如果在序列上是经典题。环上的话我们需要考虑定位一个点的问题。小trick就是一旦一只蚂蚁跨过(0/m)分界线,那么整体序号(+1/-1)所以只需要考虑有多少只蚂蚁跨越分界线即可。没写,口胡的(逃

    CF GYM101630 J Journey from Petersburg to Moscow

    印象中牛神跟我们讲过这个题啊,然后咨询了一下他们都不记得(?大概是我又记忆偏差了。。。

    做法就是类似凸优化,我们考虑枚举每条边作为第k大,然后所有边权改为max(e[i].v-V,0)然后跑dijkstra再加上V*k就可以了。

    Journey from Petersburg to Moscow

    ARC073E Ball Coloring

    发现min(Rmin,Bmin)=min,max(Rmax,Bmax)=max所以考虑最大最小怎么分配就可以了 如果两个属于一个颜色的话就需要枚举分界线 按照min排序 然后分界线以前选较大值以后选较小值

    AGC010C Cleaning

    发现非叶子节点的点权一定是路径数量的两倍 然后显然可以得到先内部配对肯定是没有问题的 然后类似于dp推上去就可以了

    SOJ408 树堆

    要是会这个题就AK了啊喂TAT

    考虑期望的线性性,有$E(x)=prod_{y=son[x]} (frac{p}{size(x)} + frac{size(x)-1}{size(x)})$然后就是简单的换根DP了TAT

    然后由于出题人毒瘤,需要考虑/0问题 所以需要自定义num类。

    (换根DP就是想不到原方程可咋整啊)

    SOJ597/596

    不写详细题解了...主要是思路值得借鉴...在非递归快速幂不好处理的时候可以考虑递归版快速幂,可以省很多不必要的东西(比如矩阵求逆 (逃

    SOJ617

    死了 好像推的还不对

    $prod_{i=0}^{n-1} sum_{j=0}^i e^{ix} -> ln \ln(prod_{i=0}^{n-1} sum_{j=0}^i e^{ix}) = prod_{i=0}^{n-1} ln(sum_{j=0}^i e^{ix}) \ln(frac{e^{nx}-1}{e^x-1})=ln(frac{frac{e^{nx}-1}{x}}{frac{e^x-1}{x}})\ln(frac{e^{nx}-1}{x}) ->ln(frac{e^y-1}{y}) \sum_{i=0}^k a_i y^i -> sum_{i=0}^{k} ai sum_{j=0}^{n-1} (jx)^i = sum_{i=0}^{k} ai sum_{j=0}^{n-1} j^ix^i$

    upd:好像差不多了 最后几步有点小问题 还是膜题解好

    SOJ625

    没啥技术含量,就是写起来真爽。(貌似进入了我的最长榜单?

    ——“联赛考这个我还不如现在就退役。”

    //Love and Freedom.
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<iostream>
    #include<queue>
    #include<vector>
    #define pa pair<int,int>
    #define fs first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define ll long long
    #define inf 20021225
    #define N 62
    using namespace std;
    int read()
    {
        int s=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
        return f*s;
    }
    struct Carbon
    {
        string pre[N];
        void init()// *
        {
            pre[1]="meth";
            pre[2]="eth";
            pre[3]="prop";
            pre[4]="but";
            pre[5]="pent";
            pre[6]="hex";
            pre[7]="hept";
            pre[8]="oct";
            pre[9]="non";
            pre[10]="dec";
            pre[11]="undec";
            pre[12]="dodec";
            pre[13]="tridec";
            pre[14]="tetradec";
            pre[15]="pentadec";
            pre[16]="hexadec";
            pre[17]="heptadec";
            pre[18]="octadec";
            pre[19]="nonadec";
            pre[20]="icos";
        }
        string print(int x)
        {
            return pre[x];
        }
        string ane(int x)
        {
            return print(x)+"ane";
        }
        string yl(int x)
        {
            return print(x)+"yl";
        }
    }C;
    struct Chain
    {
        string pre[10];
        void init()
        {
            pre[2]="di";
            pre[3]="tri";
            pre[4]="tetra";
            pre[5]="penta";
            pre[6]="hexa";
            pre[7]="hepta";
            pre[8]="octa";
            pre[9]="nona";
        }
        string print(int x)
        {
            return pre[x];
        }
    }A;
    struct edge{int to,lt;}e[N*2];
    int mc[N];
    int in[N],cnt,d[N],n;
    void add(int x,int y)
    {
        e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt; d[x]++;
        e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt; d[y]++;
    }
    bool check1()
    {
        for(int i=1;i<=n;i++)    if(d[i]>2)    return 0;
        return 1;
    }
    void sub1()
    {
        cout<<C.ane(n);
    }
    queue<int> q; int fr[N],dis[N],len,md,id[N];
    void find(int x)
    {
        while(!q.empty())    q.pop();
        memset(fr,0,sizeof(fr));
        memset(dis,0,sizeof(dis)); q.push(x); dis[x]=1;
        while(!q.empty())
        {
            int w=q.front(); q.pop();
            for(int i=in[w];i;i=e[i].lt)
            {
                int t=e[i].to; if(dis[t])    continue;
                dis[t]=dis[w]+1; fr[t]=w; q.push(t);
            }
        }
        for(int y=1;y<=n;y++)
            if(dis[y]>len)
            {
                int Y=y,D=0;
                for(int i=1;i<=dis[y];i++)
                    mc[i]=Y,D+=d[Y],Y=fr[Y];
                len=dis[y]; D-=len*2-2; md=D;
            }
            else if(dis[y]==len)
            {
                int Y=y,D=0;
                while(Y)    D+=d[Y],Y=fr[Y];
                D-=len*2-2;
                if(D>md)
                {
                    md=D; Y=y;
                    for(int i=1;i<=len;i++)
                        mc[i]=Y,Y=fr[Y];
                }
            }
    }
    int sfr[N],sdis[N],slen,smd,smc[N];
    void find(int x,int ban)
    {
        while(!q.empty())    q.pop();
        memset(sfr,0,sizeof(sfr));
        memset(sdis,0,sizeof(sdis)); q.push(x); sdis[x]=1;
        while(!q.empty())
        {
            int w=q.front(); q.pop();
            for(int i=in[w];i;i=e[i].lt)
            {
                int t=e[i].to; if(sdis[t]||t==ban)    continue;
                sdis[t]=sdis[w]+1; sfr[t]=w; q.push(t);
            }
        }
        for(int y=1;y<=n;y++)
            if(sdis[y]>slen)
            {
                int Y=y,D=0;
                for(int i=1;i<=sdis[y];i++)
                    smc[i]=Y,D+=d[Y],Y=sfr[Y];
                slen=sdis[y]; D-=len*2-2; smd=D;
            }
            else if(sdis[y]==slen)
            {
                int Y=y,D=0;
                while(Y)    D+=d[Y],Y=sfr[Y];
                D-=len*2-2;
                if(D>smd)
                {
                    smd=D; Y=y;
                    for(int i=1;i<=slen;i++)
                        smc[i]=Y,Y=sfr[Y];
                }
            }
    }
    struct gid{string pre; int id;}g[N];
    bool operator<(gid a,gid b){return a.pre<b.pre;}
    int rk[N];
    int fa[N],sz[N],dep[N];
    void dfs(int x)
    {
        sz[x]=1; dep[x]=dep[fa[x]]+1;
        for(int i=in[x];i;i=e[i].lt)
        {
            int y=e[i].to; if(y==fa[x])    continue;
            fa[y]=x; dfs(y); sz[x]+=sz[y];
        }
    }
    int check()
    {
        for(int i=2;i<len;i++)    if(d[mc[i]]>2)
            for(int j=in[mc[i]];j;j=e[j].lt)
            {
                if(e[j].to==mc[i-1]||e[j].to==mc[i+1])
                    continue;
                if(d[e[j].to]>2)    return e[j].to;
            }
        return 0;
    }
    void getperm()
    {
        dfs(mc[1]);
        vector<pa> v1;
        for(int i=2;i<len;i++)    if(d[mc[i]]>2)
            for(int j=in[mc[i]];j;j=e[j].lt)
            {
                if(e[j].to==mc[i-1]||e[j].to==mc[i+1])
                    continue;
                v1.pb(mp(i,rk[sz[e[j].to]]));
            }
        vector<pa> v2;
        for(int i=2;i<len;i++)    if(d[mc[len-i+1]]>2)
            for(int j=in[mc[len-i+1]];j;j=e[j].lt)
            {
                if(e[j].to==mc[len-i]||e[j].to==mc[len-i+2])
                    continue;
                v2.pb(mp(i,rk[sz[e[j].to]]));
            }
        for(int i=0;i<v1.size();i++)
            if(v1[i]<v2[i])    break;
            else if(v2[i]<v1[i])
            {
                reverse(mc+1,mc+len+1); break;
            }
    }
    struct printer
    {
        string pre;
        vector<int> pos;
    }prt[N];
    bool operator<(printer a,printer b){return a.pre<b.pre;}
    bool edg[N][N];
    void print()
    {
        for(int i=1;i<=n;i++)    prt[i].pre=C.pre[i];
        for(int i=2;i<len;i++)
            if(d[mc[i]]>2)
            {
                for(int j=in[mc[i]];j;j=e[j].lt)
                {
                    int to=e[j].to; if(to==mc[i-1] || to==mc[i+1])    continue;
                    int s=sz[to]; prt[s].pos.pb(i);
                }
            }
        sort(prt+1,prt+n+1); int qo=0;
        for(int i=1;i<=n;i++)
            if(prt[i].pos.size())
            {
                int po=0; if(qo) cout<<"-";    qo=1;
                for(int j=0;j<prt[i].pos.size();j++)
                {
                    if(po)    cout<<","; cout<<prt[i].pos[j]; po=1;
                }
                cout<<"-";
                cout<<A.print(prt[i].pos.size()); cout<<prt[i].pre; cout<<"yl";
            }
        cout<<C.ane(len);
    }
    string sprint(int ban)
    {
        string ans;
        for(int i=1;i<slen;i++)
            if(d[smc[i]]>2)
            {
                for(int j=in[smc[i]];j;j=e[j].lt)
                {
                    int to=e[j].to; if(to==smc[i-1] || to==smc[i+1] ||to==ban)    continue;
                    int s=sz[to]; prt[rk[s]].pos.pb(i);
                }
            }
        int qo=0;
        for(int i=1;i<=n;i++)
            if(prt[i].pos.size())
            {
                int po=0; if(qo) ans=ans+"-";    qo=1;
                for(int j=0;j<prt[i].pos.size();j++)
                {
                    if(po)    ans=ans+",";
                    ans=ans+to_string(prt[i].pos[j]); po=1;
                }
                ans=ans+"-";
                ans=ans+A.print(prt[i].pos.size()); ans=ans+prt[i].pre; ans=ans+"yl";
                prt[i].pos.erase(prt[i].pos.begin(),prt[i].pos.end());
            }
        ans=ans+C.yl(slen); return ans;
    }
    void finalprint(string aaa)
    {
        for(int i=2;i<len;i++)
            if(d[i]>2)
            {
                cout<<i<<"-("<<aaa<<")"; break;
            }
        cout<<C.ane(len);
    }
    int main()
    {
        C.init(); A.init(); n=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y); edg[x][y]=edg[y][x]=1;
        }
        if(check1())    return sub1(),0;
        for(int i=1;i<=n;i++)    g[i].pre=C.pre[i],g[i].id=i;
        sort(g+1,g+n+1);
        for(int i=1;i<=n;i++)    rk[g[i].id]=i,prt[i].pre=g[i].pre;
        for(int i=1;i<=n;i++)
            if(d[i]==1)    find(i);
        if(int k=check())
        {
            int frm=0,pos=0;
            for(int i=2;i<len;i++)    if(edg[mc[i]][k])
            {
                frm=i; pos=mc[i]; break;
            }
            find(k,pos); reverse(smc+1,smc+slen+1); dfs(smc[1]); string spc=sprint(pos);
            getperm(); finalprint(spc);
        }
        else
        {
            getperm();
            dfs(mc[1]);
            print();
        }
        return 0;
    }
    chem

    SOJ627

    这个思路好神仙...mark一下。

    考虑分治,每次找到根两边递归处理,但是如果要回溯是不是就GG了呢。

    我们来证明不需要回溯。考虑对于两个点不能有父子关系,那么父亲必须在它们中间,既然父亲在它们中间,那么当前根选在哪里根本对它们没有影响,所以根只需要满足区间内没有相同因数就可以了。

    思路很神仙,暴力去做考虑反向证明正确性。

    然后从两边往中间扫是个套路,类似逆启发式合并,因此复杂度正确。

    SOJ624

    好题.jpg

    大分类讨论QAQ

    考场上写50没写出来,然后考后改改改获得了60...

    满分其实就是50的基础上各种魔改...

    一道有趣的题qwq

    SOJ633 CF878E

    为什么这么神仙啊

    考虑从左往右做,离线以后遇到一个右端点然后找到左端点暴力合并。

    这个题的重点在于考虑到合并的贡献,一定是后头往前合并更优的= =

    SOJ635

    常见套路:仙人掌最大流就是拆环上最小的边加进去

    SOJ638

    好像也很常见套路

    考虑求多项式多次幂的某一项可以类似BSGS做到nsqrtnlgn

    然后剩下的都想到了结果第一步柿子推错了啊喂(哭 本来省选场都要阿克了的啊喂

    LOJ2083

    啊有学长好幸福(雾

    迟帅给讲的巧妙小思路 对于很多字符串统计子串都可以用的小trick 就是把原串划分成i个一段来统计长度为i的答案,这样的话匹配就是前缀匹配后缀匹配啦

    可以SA/SAM 建两遍解决ovo

    LOJ6029

    经典势能分析题(?

    就是维护区间最大值最小值然后观察差值变化即可

    具体分析见lych的博客

    校内某题

    用到的经典trick

    多项式求k次幂,转成点值后直接快速幂k次 然后在dft回来(前提是只保留前面的n项)

    还有一个经典定理

    有标号连通图计数

    $G(x) = sum _{i=0} 2^{ frac{i(i-1)} {2} } frac{x^i} {i!}$

    有答案C(x)

    $G(x) = e^{C(x)}$

    因此

    $C(x)=ln G(x)$

    SOJ673

    严格单调可以直接用差分表维护,更新直接把加上的值插入就行了。

    然后是经典的长链剖分套路(。

    SOJ669

    经典CDQ套路,其实是三维数点,但是由于只有加和查询,所以可以直接一层CDQ+BIT维护就好了。

    SOJ667.668

    都是类似的套路,考虑按照答案一层一层拓展。

    SOJ665

    在以一维排序DP复杂度降不下来的时候,考虑换一维排序,说不定就可以变成区间转移可以优化了。

    SOJ662

    手写bitset来找上一个元素和下一个元素。

    bitset中存在实现好的 find_next find_first

    貌似得把SOJ上我的AC代码拉下来才比较好= =

    md快200题了怎么拉啊

  • 相关阅读:
    git常用命令
    springcloud 心得记录
    Spring Boot整合RabbitMQ
    docker安装rabbitmq
    Linux按顺序启动多个jar的shell脚本
    idea连接docker实现一键部署
    docker安装mysql
    阿里云CentOS服务器挂载数据盘
    【selenium学习中级篇 -26】HTMLTestRunner生成测试报告
    【selenium学习中级篇 -25】Unittest框架
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/11371466.html
Copyright © 2011-2022 走看看