• ACM Amman Collegiate Programming Contest(7.22随机组队娱乐赛)


    题目链接 https://vjudge.net/contest/240074#overview

    只写一下自己做的几个题吧

    /*
    D n^2的暴力dp怎么搞都可以的 
    这里先预处理 i到j的串时候合法
    转移的时候枚举上一个状态 O1判断 
    */
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define maxn 1010
    using namespace std;
    int T,n,m,f[maxn],g[maxn][maxn];
    char s[maxn];
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            scanf("%s",s+1);
            int p,ok;
            memset(g,0,sizeof(g));
            for(int i=1;i<=n;i++){
                ok=0;p=1;
                for(int j=i+1;j<=n;j++){
                    if(s[j]==s[i])p++;
                    else p--;
                    if(s[j]==s[j-1])ok=1;
                    if((j-i+1)&1){
                        if(p==1&&ok==0)g[i][j]=1;
                    }
                    else{
                        if(p==0&&ok==0)g[i][j]=1;
                    }
                }        
            }
            memset(f,127/3,sizeof(f));f[0]=0;
            for(int i=1;i<=n;i++){
                for(int j=i-m;j<i;j++)
                    if(j>=0&&g[j+1][i]==0)
                        f[i]=min(f[i],f[j]+1);
            }
            printf("%d
    ",f[n]-1);
        }
        return 0;
    }
    /*
    n小的很 直接暴力枚举选不选的每种情况
    在此之前 从大到小排一遍序
    就可以避免把司机当成智障的情况了
     
    */ 
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int T,n,s,a[11],ans;
    int cmp(int x,int y){
        return x>y;
    }
    void Dfs(int now,int sum,int cnt){
        if(sum>=s){
            ans=max(ans,cnt);return;
        }
        if(now==n+1){
            if(sum>=s)ans=max(ans,cnt);
            return;
        }
        Dfs(now+1,sum+a[now],cnt+1);
        Dfs(now+1,sum,cnt);
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&s);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            sort(a+1,a+1+n,cmp);
            ans=0;Dfs(1,0,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
    /*
    思路应该是找到直径,连成环 
    emmmmm图的直径不会找....
    那就 先缩点,弄成树 然后找一下直径
    缩完点之后边数就是桥的个数 
    */
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #define maxn 200010
    using namespace std;
    int T,n,m,num,head[maxn],dfn[maxn],low[maxn];
    int s[maxn],top,f[maxn],topt,bl[maxn];
    int Head[maxn],N;
    queue<int>q;
    struct node{
        int v,pre;
    }e[maxn],p[maxn];
    int init(){
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void Memset(){
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(s,0,sizeof(s));
        memset(f,0,sizeof(f));
        memset(bl,0,sizeof(bl));
        memset(Head,0,sizeof(Head));
        N=0;num=0;top=0;topt=0;N=0;
    }
    void Add(int from,int to){
        num++;e[num].v=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void Ad(int from,int to){
        num++;p[num].v=to;
        p[num].pre=Head[from];
        Head[from]=num;
    }
    void Tarjan(int u,int from){
        dfn[u]=low[u]=++topt;
        s[++top]=u;f[u]=1;
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].v;
            if(v==from)continue; 
            if(dfn[v]==0){
                Tarjan(v,u);low[u]=min(low[u],low[v]);
            }
            else if(f[v])low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            N++;while(s[top]!=u){
                f[s[top]]=0;bl[s[top]]=N;top--;
            }
            f[s[top]]=0;bl[s[top]]=N;top--;
        }
    }
    int Bfs(int S){
        memset(f,0,sizeof(f));
        memset(s,0,sizeof(s));
        f[S]=1;q.push(S);
        while(!q.empty()){
            int k=q.front();q.pop();
            for(int i=Head[k];i;i=p[i].pre){
                int v=p[i].v;
                if(f[v])continue;
                f[v]=1;q.push(v);s[v]=s[k]+1;
            }
        }
        int mx=0,V=S;
        for(int i=1;i<=N;i++)
            if(mx<s[i]){
                mx=s[i];V=i;
            }
        return V;
    }
    int Bf(int S){
        memset(f,0,sizeof(f));
        memset(s,0,sizeof(s));
        f[S]=1;q.push(S);
        while(!q.empty()){
            int k=q.front();q.pop();
            for(int i=Head[k];i;i=p[i].pre){
                int v=p[i].v;
                if(f[v])continue;
                f[v]=1;q.push(v);s[v]=s[k]+1;
            }
        }
        int mx=0;
        for(int i=1;i<=N;i++)
            mx=max(mx,s[i]);
        return mx;
    }
    int main(){
        T=init();
        while(T--){
            n=init();m=init();int u,v;
            Memset();
            for(int i=1;i<=m;i++){
                u=init();v=init();
                Add(u,v);Add(v,u);
            }
            for(int i=1;i<=n;i++)
                if(dfn[i]==0)Tarjan(i,0);
            num=0;for(u=1;u<=n;u++)
                for(int i=head[u];i;i=e[i].pre){
                    v=e[i].v;
                    if(bl[u]==bl[v])continue;
                    Ad(bl[u],bl[v]);
                }
            int S=Bfs(1);
            printf("%d
    ",num/2-Bf(S));
        }
        return 0;
    }
    /*
    I
    一开始一直不知道从那下手 只是想到某些点应该固定了
    只改一次值 但是并没有找到是那些点
    好吧挺简单的就是第一个点 (寄几太弱)
    如果我们确定了最后的数都输 X 并且操作的区间长度是K
    那么第一个数只可能通过操作 1-k这个区间来搞
    同理往后推 就找到了下一个只改一次的点
    在以这个点为起点往后重复上述操作
    最后检查剩下的点是不X就好啦
    然后算一下 T*10*N*N*N
    哎呀 GG
    一开始想能不能把枚举K的那个N二分优化成log
    然后发现不单调
    这就很明显了 优化的是最后那个n*n
    一开始无脑套线段树T成智障
    第二天看题解有这么一句 :
    some contestants used segment tree to do it and got tle.....
    delete  再见
    考虑每次往后修改k个数 每个+C的过程慢了
    我们维护一个sum 代表累积到这里需要加几
    然后这个区间完事之后剪掉
    搞成On 优雅 
    */
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int T,n,k,sub[260];
    char s[260],ss[260];
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%s",ss+1);
            n=strlen(ss+1);int ok=0;
            for(k=n;k>=1;k--){
                for(char fir='0';fir<='9';fir++){
                    for(int i=1;i<=n;i++)s[i]=ss[i];
                    memset(sub,0,sizeof(sub));
                    int falg=0,sum=0,c;
                    for(int i=1;i+k-1<=n;i++){
                        sum-=sub[i];
                        s[i]=(s[i]-'0'+sum)%10+'0';
                        c=(fir-s[i]+10)%10;
                        sum+=c;s[i]=fir;sub[i+k]+=c;
                    }
                    for(int i=n-k+2;i<=n;i++){
                        sum-=sub[i];
                        s[i]=(s[i]-'0'+sum)%10+'0';
                    }
                    for(int i=1;i<n;i++)
                        if(s[i]!=s[i+1]){
                            falg=1;break;
                        }
                    if(falg==0){
                        ok=1;printf("%d
    ",k);break;
                    }
                }
                if(ok)break;
            }
        }
        return 0;
    }
    /*
    D题的加强版 需要优化
    按照D题的思路 对于每个i 在i-k - i-1 中选一个最优的且合法
    的状态转移过来 最优这件事可以用数据结构优化
    但是是不是合法 就要在研究研究
    我们到这思考 想要这个题可做 那i的上一个状态一定是从一段连续
    的区间里选  我们这次转移新构造的串是 j-i 这一块
    而题目不合法的串是010101这样子的
    倘若出现了00 或 11 后面不论加什么(长度合法)都是合法的串串
    这就很巧妙地迎合了我们的设想
    i-k 011010100101010 i-1 i 
    下面我们考虑 维护隔得i最近的还是最远的 00 11 
    (这里一开始脑子GG了 wa到挺) 
    我们选择上一个状态的左区间一定是i-k 最优的情况下
    肯定是 右区间越靠右越好 那我们就找 离得i最近的00 11
    这个东西预处理一下 存在dis里面
    然后我这个代码写的有点丑了 左边界老是取不好
    我就直接把1-k的区间预处理了一下 
    */
    #include<cstdio>
    #include<iostream>
    #define maxn 400010
    #define lc k*2
    #define rc k*2+1
    #define mid (l+r)/2
    using namespace std;
    int T,n,k,dis[maxn],f[maxn],s[maxn];
    char S[maxn];
    void Insert(int k,int l,int r,int x,int y){
        if(l==x&&r==x){
            s[k]=y;return;
        }
        if(x<=mid)Insert(lc,l,mid,x,y);
        else Insert(rc,mid+1,r,x,y);
        s[k]=min(s[lc],s[rc]);
    }
    int Query(int k,int l,int r,int x,int y){
        if(x<=l&&y>=r)return s[k];
        int ret=1e9;
        if(x<=mid)ret=min(ret,Query(lc,l,mid,x,y));
        if(y>mid)ret=min(ret,Query(rc,mid+1,r,x,y));
        return ret;
    } 
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%s",&n,&k,S+1);
            for(int i=0;i<=n*4;i++){
                s[i]=1e9;f[i]=1e9;
            }
            int pos=0; 
            for(int i=2;i<=n;i++){
                if(S[i]==S[i-1])pos=i-2;
                dis[i]=pos;
            }    
            int falg=0;f[1]=1;
            Insert(1,1,n,1,1);
            for(int i=2;i<=k;i++){
                if(S[i]==S[i-1])falg=1;
                if(falg)f[i]=1;
                else f[i]=i;
                Insert(1,1,n,i,f[i]);
            }
            for(int i=k+1;i<=n;i++){
                if(dis[i]<i-k)f[i]=f[i-1]+1;
                else f[i]=Query(1,1,n,i-k,dis[i])+1;
                Insert(1,1,n,i,f[i]);
            }
            printf("%d
    ",f[n]-1);
        }
        return 0;
    }
  • 相关阅读:
    apt-get install jdk
    progit-zh(Git中文文档)
    indexedDB bootstrap angularjs 前端 MVC Demo
    状态模式
    使用TypeConverter类
    wpf 全局异常捕获处理
    WPF 中的形状和基本绘图概述
    WPF设计自定义控件
    WPF快速入门系列(9)——WPF任务管理工具实现
    WPF快速入门系列(8)——MVVM快速入门
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/9373867.html
Copyright © 2020-2023  润新知