zoukankan      html  css  js  c++  java
  • CSP2019

    $CSPspace S$

    格雷码

    $solution:$

    直接模拟即可。

    时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    void solve(unsigned long long N,unsigned long long K){
        if(N==0) return;
        unsigned long long p=(1ull<<(N-1ull));
        if(p>=K){printf("0");solve(N-1,K);return;}
        printf("1");solve(N-1,2ull*p-K+1ull);return;
    }
    unsigned long long n,k;
    signed main(){
        cin>>n>>k;
        if(n==64ull&&k==18446744073709551615ull){
            printf("1");
            for(int i=2;i<=64;i++) printf("0");printf("
    ");
            return 0;
        } 
        k++;
        solve(n,k);printf("
    ");return 0;
    }
    View Code

    括号树

    $solution:$

    考虑从 $1$ 号点到 $u$ 号点的括号序列中有多少个后缀是括号序列的,这个可以通过栈做简单的 $dp$ 得到。

    时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=500001;
    int fa[MAXN],N;
    vector<int> vec[MAXN];
    char str[MAXN];int sta[MAXN],top,f[MAXN],A;
    void dfs(int u,int Ans){
        int del=0;bool ins=0;
        if(str[u]=='(') ins=1,sta[++top]=u;
        else if(str[u]==')'&&top){int i=sta[top];del=i;f[u]=f[fa[i]]+1;top--;Ans+=f[u];} 
        A^=(u*Ans);for(int i=0;i<vec[u].size();i++) dfs(vec[u][i],Ans);
        if(del) sta[++top]=del;if(ins) top--;
        return;
    }
    signed main(){
        N=read();scanf("%s",str+1);
        for(int i=2;i<=N;i++) vec[(fa[i]=read())].push_back(i);
        dfs(1,0);
        printf("%lld
    ",A);return 0;
    }/*
    5
    )()()
    1 1 2 1 
    */
    View Code

    Emiya 家今天的饭

    $solution:$

    考虑 $O(n^3m)$ $dp$ 的优化,因为此 $dp$ 的状态 $f_{i,j,k,p}$ 表示当前考虑第 $i$ 列的容斥,其中在前 $j$ 行中选择 $k$ 个为第 $i$ 列,$p$ 个不为第 $i$ 列,因为状态数位 $O(n^3m)$ 转移 $O(1) $ ,所以总时间复杂度为 $O(n^3m)$ 。

    而我们发现若 $k-pgeq 0$ 即可以在容斥时减去,所以设 $g_{i,j,k}$ 表示当前考虑第 $i$ 列的容斥,其中在前 $j$ 行选择第 $i$ 列的减去选择但没有选择第 $i$ 列的等于 $k$ 个,因为转移 $O(1)$ 所以时间为 $O(n^2m)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define mod 998244353
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=111;
    const int MAXM=2011;
    int N,M,f[MAXN][MAXN],g[MAXN][MAXN<<1],S[MAXN],A[MAXN][MAXM],Ans;
    int Mod(int x){return ((x%mod)+mod)%mod;}
    signed main(){
        N=read(),M=read();
        for(int i=1;i<=N;i++){
            for(int j=1;j<=M;j++) S[i]+=(A[i][j]=read()),S[i]%=mod;
        }
        f[0][0]=1;
        for(int i=1;i<=N;i++){
            for(int j=0;j<=N;j++){
                f[i][j]=f[i-1][j];
                if(j) f[i][j]+=f[i-1][j-1]*S[i];f[i][j]%=mod;
                if(i==N&&j) Ans+=f[i][j],Ans%=mod;    
            }
        }
        for(int i=1;i<=M;i++){
            memset(g,0,sizeof(g));
            g[0][N]=1;
            for(int j=1;j<=N;j++){
                for(int k=0;k<=2*N;k++){
                    g[j][k]=g[j-1][k]+g[j-1][k+1]*Mod(S[j]-A[j][i]);
                    if(k) g[j][k]+=g[j-1][k-1]*A[j][i];
                    g[j][k]%=mod;
                }
            }
            for(int j=1;j<=N;j++) Ans-=g[N][N+j],Ans=Mod(Ans);
        }printf("%lld
    ",Ans);return 0;
    }
    View Code

    划分

     $solution:$

    考虑 $O(n^3)$ 的暴力 $dp$ ,设 $f_{i,j}$ 表示最后一段为 $[i,j]$ 的最小代价,通过打表可以发现 $f_{i,j}leq f_{i,j-1}$ 。

    所以说问题就转换成了求 $f$ 有解的最大右端点,只维护 $f$ 中的转移点即可,不需要管 $f$ 的具体值,在最后计算答案即可。

    设 $F_i$ 表示 $f_{i}$ 的最右转移点,即 $(F_i,i]$ 为若 $f$ 值最小区间,则 $F_i=max{j}space(S_i-S_jgeq S_j-S_{F_j})$ ,即 $S_igeq 2 imes S_j-S_{F_j}$ 。

    直接单调队列优化即可,而最后可以用 $int128$ 或手写高精度。时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define LL long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=40000001;
    int N,A[MAXN],opt,B[MAXN],P[MAXN],L[MAXN],R[MAXN],u;
    void Maker(){
        if(!opt){for(int i=1;i<=N;i++) A[i]=read();return;}
        int pw=1;for(int i=1;i<=30;i++) pw*=2;
        int x=read(),y=read(),z=read();B[1]=read(),B[2]=read();int m=read();
        for(int i=3;i<=N;i++) B[i]=(LL)((LL)x*B[i-1]+(LL)y*B[i-2]+(LL)z)%pw;
        for(int i=1;i<=m;i++) P[i]=read(),L[i]=read(),R[i]=read();
        int ps=0;
        for(int i=1;i<=N;i++){
            if(!(P[ps-1]<i&&i<=P[ps])) ps++;
            A[i]=B[i]%(R[ps]-L[ps]+1)+L[ps];
        }return;
    }
    int f[MAXN],head=1,tail=1,Que[MAXN];
    LL S[MAXN];
    LL calc(int id){return 2ll*S[id]-S[f[id]];}
    void write(__int128 u){if(!u) return;write(u/10);putchar((u%10)+'0');return;}
    int main(){
        N=read();opt=read();Maker();
        for(int i=1;i<=N;i++) S[i]=S[i-1]+(LL)A[i];
        for(int i=1;i<=N;i++){
            while(head<tail&&calc(Que[head+1])<=S[i]) head++;f[i]=Que[head];
            while(head<tail&&calc(Que[tail])>=calc(i)) tail--;Que[++tail]=i;
        }
        __int128 Ans=0;u=N;
        while(u){
            Ans+=(__int128)(S[u]-S[f[u]])*(__int128)(S[u]-S[f[u]]);
            u=f[u];
        }
        write(Ans);printf("
    ");
        return 0;
    }
    View Code

    树的重心

    $solution:$

    考虑 $u$ 号点的贡献,设 $f_u$ 表示以 $u$ 为根子树下子树最大的。

    考虑如何再删掉 $(x,fa_x)$ 这条边时重心为 $u$ 。

    若 $x$ 为 $u$ 的祖先,则
    $$
    egin{equation}
    left{
    egin{array}{**lr**}
    f_uleq lfloordfrac{siz_x}{2} floor\
    siz_x-siz_uleq lfloordfrac{siz_x}{2} floor
    end{array}
    ight.
    end{equation}
    $$
    即 $2cdot f_uleq siz_xleq 2cdot siz_u$ 。

    若 $x$ 在 $u$ 的子树下,可得 $2cdot siz_v-Nleq siz_xleq min{N-2cdot f_u,2cdot siz_u-N}$ 。而 $f_u$ 表示除了 $v$ 以外最大子树。

    其余情况则 $N-2cdot siz_uleq siz_xleq N-2cdot f_u$ 。

    对于祖先情况可以直接在 $dfs$ 遍历是用树状数组维护,子树可以 $dfs$ 序后树状数组维护,其余情况可以通过整体减去祖先与子树得到。

    时间复杂度 $O(nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define LL long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=300001;
    struct node{
        int u,v,nex;
    }x[MAXN<<1];
    int T,N,head[MAXN],cnt,dfn[MAXN],rev[MAXN],tot,fa[MAXN],f1[MAXN],f2[MAXN],siz[MAXN];
    inline void add(int u,int v){
        x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
    }
    inline void dfs(int u,int fath){
        siz[u]=1;fa[u]=fath;dfn[u]=++tot,rev[tot]=u;
        for(register int i=head[u];i!=-1;i=x[i].nex){
            if(x[i].v==fath) continue;
            dfs(x[i].v,u);
            siz[u]+=siz[x[i].v];int res=siz[x[i].v];
            if(res>=f1[u]) f2[u]=f1[u],f1[u]=res;
            else if(res>=f2[u]) f2[u]=res;
        }return;
    }
    int Num[4][MAXN];
    struct BIT{
        int Ans[MAXN];
        void clear(){memset(Ans,0,sizeof(Ans));}
        int lowbit(int x){return x&-x;}
        void Modify(int x,int w){for(;x<=N;x+=lowbit(x)) Ans[x]+=w;return;}
        int Query(int x){if(x==-1) return 0;int res=0;for(;x;x-=lowbit(x)) res+=Ans[x];return res;}
        void ins(int x,int w){Modify(x,w);return;}
        int Que(int l,int r){if(l>r) return 0;return Query(r)-Query(l-1);}
    }bit;
    struct Node{
        int opt1,opt2,l,r,U;
    };
    vector<Node> vec[MAXN]; 
    inline void dfs1(int u,int fath){
        if(u!=1) bit.ins(siz[u],1);
        for(register int i=0;i<vec[u].size();++i){
            Num[vec[u][i].opt1][u]+=vec[u][i].opt2*bit.Que(vec[u][i].l,vec[u][i].r);
            if(vec[u][i].opt1==3){
                int L=vec[u][i].l,R=vec[u][i].r;
                Num[vec[u][i].opt1][u]+=vec[u][i].opt2*((L<=siz[1])&&(siz[1]<=R));
            }
        }
        for(register int i=head[u];i!=-1;i=x[i].nex){
            if(x[i].v==fath) continue;
            dfs1(x[i].v,u);
        }
        if(u!=1) bit.ins(siz[u],-1);
        return;
    }
    signed main(){
        T=read();
        while(T--){
            tot=0;cnt=0;
            memset(Num,0,sizeof(Num));
            memset(head,-1,sizeof(head));memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));
            N=read();
            for(register int i=1;i<N;++i){int u=read(),v=read();add(u,v),add(v,u);}dfs(1,0);
            for(register int i=1;i<=N;++i) vec[i].clear();bit.clear();
            for(register int i=1;i<=N;++i){
                Node e;e.opt1=1,e.opt2=1,e.l=2*f1[i],e.r=2*siz[i];
                e.l=max(e.l,0),e.r=min(e.r,N);
                vec[i].push_back(e);
                int L=N-2*siz[i],R=N-2*f1[i];L=max(L,0),R=min(R,N);
                e.opt1=3,e.opt2=-1,e.l=L,e.r=R;
                vec[i].push_back(e);
            }dfs1(1,0);
            
            
            bit.clear();for(int i=1;i<=N;i++) vec[i].clear();
            for(register int xx=1;xx<=N;++xx){
                for(register int i=head[xx];i!=-1;i=x[i].nex){
                    if(x[i].v==fa[xx]) continue;
                    Node e;int EE=0;
                    if(f1[xx]==siz[x[i].v]) EE=f2[xx];
                    else EE=f1[xx];
                    e.opt1=2,e.opt2=1,e.l=2*siz[x[i].v]-N,e.r=min(N-2*EE,2*siz[xx]-N);e.l=max(e.l,0),e.r=min(e.r,N);e.U=xx;
                    vec[dfn[x[i].v]+siz[x[i].v]-1].push_back(e);
                    e.opt2=-1;
                    vec[dfn[x[i].v]-1].push_back(e);
                }
                int L=N-2*siz[xx],R=N-2*f1[xx];L=max(L,0),R=min(R,N);
                Node e;e.opt1=3,e.opt2=-1,e.l=L,e.r=R;e.U=xx;
                vec[dfn[xx]+siz[xx]-1].push_back(e);
                e.opt2=1;vec[dfn[xx]].push_back(e);
            }
            for(register int i=1;i<=N;++i){
                bit.ins(siz[rev[i]],1);
                for(register int j=0;j<vec[i].size();++j){
                    Node e;e=vec[i][j];
                    Num[e.opt1][e.U]+=e.opt2*bit.Que(e.l,e.r);
                }
            }
            for(register int i=1;i<=N;++i){int L=N-2*siz[i],R=N-2*f1[i];L=max(L,0),R=min(R,N);Num[3][i]+=bit.Que(L,R);}
            LL Ans=0;
            for(register int i=1;i<=N;++i) Ans+=(LL)i*(LL)(Num[1][i]+Num[2][i]+Num[3][i]);
            printf("%lld
    ",Ans);
        }
    }
    View Code

    $CSPspace J$

    数字游戏

    $solution:$

    直接模拟。时间复杂度 $O(1)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1001;
    char str[MAXN];
    int main(){
    //    freopen("number.in","r",stdin);
    //    freopen("number.out","w",stdout);
        scanf("%s",str+1);int len=strlen(str+1),Ans=0;
        for(int i=1;i<=len;i++) Ans+=(str[i]=='1');
        printf("%d
    ",Ans);return 0;
    }
    View Code

    公交换乘

    $solution:$

    线段树二分模板题。时间复杂度 $O(nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=100001;
    struct node{
        int w,t;
    }g[MAXN];
    int N,tot,Ans;
    struct Segment_Tree{
        int Maxn[MAXN<<2];
        void Modify(int k,int l,int r,int x,int y,int w){
            if(x<=l&&r<=y) {Maxn[k]=w;return;}
            int mid=l+r>>1;
            if(x<=mid) Modify(k<<1,l,mid,x,y,w);
            if(mid<y) Modify(k<<1|1,mid+1,r,x,y,w);
            Maxn[k]=max(Maxn[k<<1],Maxn[k<<1|1]);
        }
        int Qpos(int k,int l,int r,int w){
            if(l==r) return l;
            int mid=l+r>>1;
            if(Maxn[k<<1]>=w) return Qpos(k<<1,l,mid,w);
            if(Maxn[k<<1|1]>=w) return Qpos(k<<1|1,mid+1,r,w);
            return -1;
        }
    }Segment;
    signed main(){
    //    freopen("transfer.in","r",stdin);
    //    freopen("transfer.out","w",stdout);
        N=read();int l=1;
        for(int i=1;i<=N;i++){
            int opt=read(),w=read(),t=read();
            if(opt==0){g[++tot].w=w,g[tot].t=t;Segment.Modify(1,1,N,tot,tot,w);Ans+=w;continue;}
            while(l<=tot&&t-g[l].t>45){Segment.Modify(1,1,N,l,l,0);l++;}
            int u=Segment.Qpos(1,1,N,w);
            if(u==-1) {Ans+=w;;continue;}
            Segment.Modify(1,1,N,u,u,0);continue;
    //        printf("i:%d l:%d
    ",i,l);
        }printf("%lld
    ",Ans);return 0;
    }
    View Code

    纪念品

    若 $i$ 天买进 $j$ 天卖出可以看成 $i$ 天买 ,$i+1$ 天卖后再买。做 $T-1$ 次完全背包即可。时间复杂度 $O(10^4cdot Tcdot N)$

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXA=10001;
    const int MAXN=101;
    int T,N,M,f[MAXA],A[MAXN][MAXN],Maxn;
    int main(){
    //    freopen("4.in","r",stdin);
        T=read(),N=read(),M=read();
        if(T==1){printf("%d
    ",M);return 0;}
        for(int i=1;i<=T;i++)
            for(int j=1;j<=N;j++) A[i][j]=read();Maxn=M;
        for(int i=1;i<T;i++){
            memset(f,0,sizeof(f));
            for(int j=0;j<=Maxn;j++) f[j]=j;
            for(int j=0;j<=Maxn;j++)
                for(int k=1;k<=N;k++) if(j>=A[i][k]){
                    f[j]=max(f[j],f[j-A[i][k]]+A[i+1][k]);
                }
            for(int j=0;j<=Maxn;j++) Maxn=max(Maxn,f[j]);
        }printf("%d
    ",Maxn);return 0;
    }/*
    6 1 100
    50
    20
    25
    20
    25
    50
    */
    View Code

    加工零件

    分奇偶跑最短路即可,时间复杂度 $O(n+m+q)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=100001;
    struct node{
        int u,v,w,nex;
    }x[MAXN<<1];
    int head[MAXN],cnt,f[MAXN][2];
    void add(int u,int v,int w){
        x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
    }
    int n,m,vis[MAXN][2],q,siz[MAXN];
    priority_queue<pair<int,pair<int,int> > > Que;
    void dijkstra(){
        memset(f,127/3,sizeof(f));f[1][0]=0;Que.push(make_pair(0,make_pair(1,0)));
        while(!Que.empty()){
            int u=Que.top().second.first,opt=Que.top().second.second;Que.pop();if(vis[u][opt]) continue;
            vis[u][opt]=1;
            for(int i=head[u];i!=-1;i=x[i].nex){
                int W=f[u][opt]+x[i].w;
                if(f[x[i].v][W&1]>W){
                    f[x[i].v][W&1]=W;Que.push(make_pair(-f[x[i].v][W&1],make_pair(x[i].v,W&1)));
                }
            }
        }
    }
    signed main(){
    //    freopen("work.in","r",stdin);
    //    freopen("work.out","w",stdout);
        memset(head,-1,sizeof(head));
        n=read(),m=read(),q=read();
        for(int i=1;i<=m;i++){
            int u=read(),v=read();
            add(u,v,1),add(v,u,1);siz[u]++,siz[v]++;
        }
        dijkstra();
        while(q--){
            int u=read(),L=read();
            if(u==1&&siz[1]==0){printf("No
    ");continue;}
            if(f[u][L&1]<=L){printf("Yes
    ");continue;}
            printf("No
    ");continue;
        }
    }/*
    10 6 5
    
    4 7
    2 4
    4 5
    3 2
    5 7
    8 6
    
    3 1
    8 2
    4 1
    5 1
    1 4
    
    */
    View Code
  • 相关阅读:
    PHPMyAdmin Docker
    Appium环境搭建-Mac版本
    上传项目到GitHub遇到的错误
    上传项目到GitHub(总结)
    C++ 简单代码,语法参照
    vs2010学习
    线性拟合-实验报告
    我的图形学程序
    网页版 连连看 html5实现
    带无线功能的笔记本 配置无线局域网 共享上网
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11884401.html
Copyright © 2011-2022 走看看