zoukankan      html  css  js  c++  java
  • 湖南雅礼培训 1.2

    模拟赛

    串(string)

    【题目描述】
    给定一个由小写字母组成的字符串 s,每次你可以删去它的一个非回文子串,
    求删成空串的最小次数。
    【输入数据】
    第一行一个整数 t 表示数据组数。
    每组数据第一行一个整数 n 表示字符串长度,第二行一个字符串 s。
    【输出数据】
    每组数据输出一行一个整数表示答案,如果无法删成空串输出-1。
    【样例输入】
    2
    7
    abcdcba
    3
    xxx
    【样例输出】
    2
    -1
    【样例解释】
    对于第一个样例,一种最优方案为 abcdcba->adcba->空串。
    【数据范围】
    对于 30%的数据,n<=10。
    对于 60%的数据,n<=100。
    对于 100%的数据,t<=20,n<=10^5。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 110
    #define INF 0x7fffffff
    using namespace std;
    int ans;
    struct node{
        string s;
        int len;
    };
    void solve(node now,int step){//已经进行了step次 
        if(step>=ans)return;
        for(int l=0;l<now.len;l++){
            for(int r=l+1;r<now.len;r++){
                int ll=l,rr=r;bool flag=0;
                while(ll<=rr){
                    if(now.s[ll]!=now.s[rr]){flag=1;break;}
                    else ll++,rr--;
                }
                if(flag==0)continue;
                node nxt;nxt.s="";nxt.len=0;
                for(int i=0;i<l;i++)nxt.s+=now.s[i],nxt.len++;
                for(int i=r+1;i<now.len;i++)nxt.s+=now.s[i],nxt.len++;
                if(nxt.len==0){
                    ans=min(ans,step+1);
                    return;
                }
                solve(nxt,step+1);
            }
        }
    }
    int main(){
    //    freopen("Cola.txt","r",stdin);
        freopen("string.in","r",stdin);freopen("string.out","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--){
            ans=INF;
            node str;
            scanf("%d",&str.len);cin>>str.s;
            solve(str,0);
            if(ans<INF)printf("%d
    ",ans);
            else puts("-1");
        }
        return 0;
    }
    30分 暴力
    /*
        首先如果s不是回文串答案为1。
        考虑对于1<=i<n,是否都满足s[1..i]和s[i+1..n]至少有一个是回文的。如果不满足那么答案为2。
        如果满足的话,如果s[1]=s[2],那么s只会形如aaaaa或aaabaaa;如果s[1]!=s[2],那么s只会形如abababa。这三种情况都是无解的。
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n;
    char s[100010];
    int main(){
        freopen("string10.in","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%d%s",&n,s+1);
            int l=1,r=n;
            bool flag=0;
            while(l<=r){
                if(s[l]!=s[r]){flag=1;break;}//不是回文串 
                l++,r--;
            }
            if(flag){puts("1");continue;}
            for(int i=1;i<=n;i++){//枚举中间点 
                l=1,r=i;
                bool flag1=0,flag2=0;
                while(l<=r){
                    if(s[l]!=s[r]){flag1=1;break;}
                    l++,r--;
                }
                if(flag1==0)continue;
                l=i+1,r=n;
                while(l<=r){
                    if(s[l]!=s[r]){flag2=1;break;}
                    l++;r--;
                }
                if(flag1&&flag2){flag=1;puts("2");break;}
            }
            if(!flag)puts("-1");
        }
        return 0;
    }
    60分 结论+暴力判断是否回文
    /*
        不是直接求得回文串 
        而是根据下面的三种情况得到的
        如果不是下面三种情况
        就肯定是满足条件的
        如果满足的话,如果s[1]=s[2],那么s只会形如aaaaa或aaabaaa;如果s[1]!=s[2],那么s只会形如abababa。这三种情况都是无解的。
        也就是其它情况都是输出2
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n;
    char s[100010];
    int main(){
        freopen("string9.in","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%d%s",&n,s+1);
            int l=1,r=n;
            bool flag=0;
            while(l<=r){
                if(s[l]!=s[r]){flag=1;break;}//不是回文串 
                l++,r--;
            }
            if(flag){puts("1");continue;}
            bool f1=0,f2=0,f3=0;
            for(int i=1;i<=n;i++){
                if(i>1&&s[i]!=s[i-1])f1=1;//不满足第一个条件 
                if(i>2&&s[i]!=s[i-2])f2=1;//不满足第二个条件 
            }
            int mid=(n/2)+1;
            for(int i=2;i<mid;i++)if(s[i]!=s[i-1])f3=1;
            for(int i=mid+2;i<=n;i++)if(s[i]!=s[i-1])f3=1;
            if(f1&&f2&&f3)puts("2");//三个条件都不满足 
            else puts("-1");
        }
        return 0;
    }
    100分


    变量(variable)


    【题目描述】
    有 n 个变量 w[1]~w[n],每个变量可以取 W 或-W。
    有 p 个式子,形如 Hi=ai|w[xi]-w[yi]|+bi|w[yi]-w[zi]|+ci|w[zi]-w[xi]|
    +di(w[xi]-w[yi])+ei(w[yi]-w[zi])+fi(w[zi]-w[xi])。
    有 q 个条件,形如 w[x]<=w[y]或 w[x]=w[y]或 w[x]<w[y]。
    最小化 sigma(wi)+sigma(Hi)。
    【输入数据】
    第一行一个整数 t 表示数据组数。
    每组数据第一行四个整数 n,W,p,q 表示节点数。
    接下来 p 行每行九个整数 xi,yi,zi,ai,bi,ci,di,ei,fi。
    接下来 q 行每行三个整数 x,y,r。
    r=0 表示 w[x]<=w[y];r=1 表示 w[x]=w[y];r=2 表示 w[x]<w[y]。
    保证存在方案。
    【输出数据】
    每组数据输出一行一个整数表示 sigma(wi)+sigma(Hi)的最小值。
    【样例输入】
    1
    3 1 1 1
    1 2 3 1 1 1 1 1 1
    1 2 2
    【样例输出】
    3
    【数据范围】
    对于 30%的数据,n<=15,p,q<=20。
    对于 100%的数据,t<=10,n<=500,p,q<=1000,1<=W<=10^6,
    0<=ai,bi,ci,di,ei,fi<=1000。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #define maxn 510
    #define INF 0x7fffffff
    using namespace std;
    int ans,n,W,p,q,link[maxn][maxn],w[maxn];
    struct node{
        int x,y,z,a,b,c,d,e,f;
    }qu[maxn];
    struct Node{
        int x,y,v;
    }r[maxn];
    bool check(int sta){
        for(int i=1;i<=n;i++){
            w[i]=sta&(1<<(i-1));
            if(w[i]!=0)w[i]=W;
            else w[i]=-W;
        }
        for(int i=1;i<=q;i++){
            if(r[i].v==0){
                if(w[r[i].x]>w[r[i].y])return 0;
            }
            else if(r[i].v==1){
                if(w[r[i].x]!=w[r[i].y])return 0;
            }
            else if(r[i].v==2){
                if(w[r[i].x]>=w[r[i].y])return 0;
            }
        }
        return 1;
    }
    int main(){
    //    freopen("Cola.txt","r",stdin);
        freopen("variable.in","r",stdin);freopen("variable.out","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--){
            ans=INF;
            scanf("%d%d%d%d",&n,&W,&p,&q);
            for(int i=1;i<=p;i++)scanf("%d%d%d%d%d%d%d%d%d",&qu[i].x,&qu[i].y,&qu[i].z,&qu[i].a,&qu[i].b,&qu[i].c,&qu[i].d,&qu[i].e,&qu[i].f);
            for(int i=1;i<=q;i++)scanf("%d%d%d",&r[i].x,&r[i].y,&r[i].v);
            for(int sta=0;sta<(1<<n);sta++){
                if(!check(sta))continue;
                int s1=0,s2=0;
                for(int i=1;i<=n;i++)s1+=w[i];
                for(int i=1;i<=p;i++){
                    s2+=qu[i].a*abs(w[qu[i].x]-w[qu[i].y])+qu[i].b*abs(w[qu[i].y]-w[qu[i].z])+qu[i].c*abs(w[qu[i].z]-w[qu[i].x]);
                    s2+=qu[i].d*(w[qu[i].x]-w[qu[i].y])+qu[i].e*(w[qu[i].y]-w[qu[i].z])+qu[i].f*(w[qu[i].z]-w[qu[i].x]);
                }
                ans=min(ans,s1+s2);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    10分 暴力,开long long 能得30分
    /*
        每个变量建一个点i,S向i连边,i向T连边。割这两条边分别表示取-W和取W。对于x[i]*w[i],讨论正负往其中一条边上加权值。
        对于y[j]*|w[a[j]]-w[b[j]]|,在a[j]和b[j]间连权值为2y[j]的无向边。
        对于限制,wa<wb等价于wa=-W且wb=W;wa=wb就在a和b间连权值为正无穷的无向边;wa<=wb就a向b连权值为正无穷的单向边。最后求最小割即可。
        时间复杂度O(t*maxflow(n,n+p+q))
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    #define INF 0x3f3f3f3f
    using namespace std;
    int n,m,s,t,op,oq,head[10005],num=1,dis[10005],vis[10005],mp[510][510],val[510],cur[10005];
    long long w;
    struct node{
        int to,pre,cap,flow;
    }e[100005];
    long long qread(){
        int j=1;long long i=0;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();}
        while(ch<='9'&&ch>='0'){i=i*10+ch-'0';ch=getchar();}
        return i*j;
    }
    void Insert(int from,int to,int v){
        e[++num].to=to;e[num].cap=v;e[num].flow=0;e[num].pre=head[from];head[from]=num;
        e[++num].to=from;e[num].cap=0;e[num].flow=0;e[num].pre=head[to];head[to]=num;
    }
    int bfs(){
        for(int i=1;i<=t;i++)dis[i]=INF,vis[i]=0,cur[i]=head[i];
        queue<int>q;q.push(s);dis[s]=0;vis[s]=1;q.push(s);
        while(!q.empty()){
            int now=q.front();q.pop();
            for(int i=head[now];i;i=e[i].pre){
                int to=e[i].to;
                if(!vis[to]&&e[i].cap-e[i].flow>0){
                    vis[to]=1;dis[to]=dis[now]+1;q.push(to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int now,int flow){
        if(now==t||flow==0)return flow;
        int delta,rest=0;
        for(int &i=cur[now];i;i=e[i].pre){
            int to=e[i].to;
            if(dis[now]+1==dis[to]){
                delta=dfs(to,min(flow,e[i].cap-e[i].flow));
                if(delta>0){
                    e[i].flow+=delta;
                    e[i^1].flow-=delta;
                    rest+=delta;
                    flow-=delta;
                    if(flow==0)break;
                }
            }
        }
        return rest;
    }
    int dinic(){
        int maxflow=0;
        while(bfs())maxflow+=dfs(s,INF);
        return maxflow;
    }
    int main(){
        freopen("variable9.in","r",stdin);
        int T;scanf("%d",&T);
        while(T--){
            scanf("%d",&n);w=qread();scanf("%d%d",&op,&oq);
            memset(head,0,sizeof(head));num=1;
            memset(mp,0,sizeof(mp));
            memset(val,0,sizeof(val));
            for(int i=1;i<=n;i++)val[i]=1;
            for(int i=1;i<=op;i++){
                int xi,yi,zi,ai,bi,ci,di,ei,fi;
                scanf("%d%d%d%d%d%d%d%d%d",&xi,&yi,&zi,&ai,&bi,&ci,&di,&ei,&fi);
                val[xi]+=di-fi;
                val[yi]+=ei-di;
                val[zi]+=fi-ei;
                if(xi<yi)mp[xi][yi]+=ai;else mp[yi][xi]+=ai;
                if(yi<zi)mp[yi][zi]+=bi;else mp[zi][yi]+=bi;
                if(zi<xi)mp[zi][xi]+=ci;else mp[xi][zi]+=ci;
            }
            int mx=0;
            for(int i=1;i<=n;i++)mx=max(mx,abs(val[i]));
            mx++;
            s=2*n+1;t=2*n+2;
            for(int i=1;i<=n;i++){
                Insert(s,i,mx+val[i]);
                Insert(i,i+n,INF);
                Insert(i+n,t,mx-val[i]);
            }
            for(int i=1;i<=n;i++)
                for(int j=i+1;j<=n;j++){
                    if(mp[i][j]==0)continue;
                    Insert(i+n,j,2*mp[i][j]);
                    Insert(j+n,i,2*mp[i][j]);
                }
            for(int i=1;i<=oq;i++){
                int xi,yi,zi;
                scanf("%d%d%d",&xi,&yi,&zi);
                if(zi==0)Insert(yi+n,xi,INF);
                if(zi==1)Insert(xi+n,yi,INF),Insert(yi+n,xi,INF);
                if(zi==2)Insert(s,xi,INF),Insert(yi+n,t,INF);
            }
            long long ans=1LL*(dinic()-mx*n)*w;
            cout<<ans<<endl;
        }
        return 0;
    }
    100分 最小割


    取石子(stone)


    【题目描述】
    有 n 堆石子,第 i 堆有 xi 个。
    Alice 和 Bob 轮流取石子(先后手未定),Alice 每次从一堆中取走 a 个,Bob
    每次从一堆中取走 b 个,无法操作者输。
    不难发现只会有四种情况:Alice 必胜;Bob 必胜;先手必胜;后手必胜。
    你需要选定若干堆石子(共有 2^n 种方案),Alice 和 Bob 只能在你选出的堆
    中取,问以上四种情况对应的方案数。
    【输入数据】
    第一行三个整数 n,a,b,第二行 n 个整数 x1~xn。
    【输出数据】
    一行四个整数,分别表示 Alice 必胜、Bob 必胜、先手必胜和后手必胜的方
    案数,对 10^9+7 取模。
    【样例输入】
    2 2 3
    2 3
    【样例输出】
    2 0 1 1
    【样例解释】
    选定空集时后手必胜,选定{2}时 Alice 必胜,选定{3}时先手必胜,选定{2,3}时 Alice
    必胜。
    【数据范围】
    对于 10%的数据,n,xi<=5。
    对于 50%的数据,n<=20。
    对于另外 10%的数据,a=b。
    对于又另外 20%的数据,a=1。
    对于 100%的数据,1<=n<=100000,1<=a,b,xi<=10^9。

    /*
        不妨假设a<b。
        每堆石子先对a+b取模,然后可以分为4种:
        (1)    xi<a,没用。
        (2)    a<=xi<b,只要存在则a必胜。
        (3)    b<=xi<2a,只和奇偶性有关。
        (4)    2a<=xi,存在至少2个则a必胜,存在1个且(3)为偶数则先手必胜,存在1个且(3)为奇数则a必胜,不存在且(3)为奇数则先手必胜,不存在且(3)为偶数则后手必胜。
        时间复杂度O(n)
    */
    #include<bits/stdc++.h>
    #define L long long
    using namespace std;
    const int q=1000000007;
    int n,a,b,x[4],f[4];
    inline int power(int a,int b)
    {
        if(!b)
          return 1;
        int c=power(a,b>>1);
        c=(L)c*c%q;
        if(b&1)
          c=(L)c*a%q;
        return c;
    }
    int main()
    {
        freopen("stone.in","r",stdin);
        freopen("stone.out","w",stdout);
        int i,j,k=0;
        scanf("%d%d%d",&n,&a,&b);
        if(a>b)
          swap(a,b),k=1;
        for(i=1;i<=n;i++)
          {
           scanf("%d",&j);
           j%=a+b;
           x[(j>=a)+(j>=b)+(j>=b && j>=2*a)]++;
          }
        f[0]=((L)(power(2,x[1])-1)*power(2,x[2]+x[3])+(L)(power(2,x[3])-x[3]-1+q)*power(2,x[2])+(L)x[3]*(x[2]?power(2,x[2]-1):0))%q;
        f[2]=((x[2]?power(2,x[2]-1):0)+(L)x[3]*(x[2]?power(2,x[2]-1):1))%q;
        f[3]=(x[2]?power(2,x[2]-1):1);
        for(i=0;i<4;i++)
          f[i]=(L)f[i]*power(2,x[0])%q;
        if(k)
          swap(f[0],f[1]);
        for(i=0;i<4;i++)
          printf("%d ",f[i]);
        printf("
    ");
        return 0;
    }
    100分
  • 相关阅读:
    Nagios经check_http监视web申请书server多个tomcat维修
    一个测试SQL2005数据库连接JSP档
    android 36 线程通信
    android 35 ListView增删改差
    android 34 ListView进阶
    android 33 对话框控件
    android 32 Gallery:横着滚动的列表
    android 31 GridView
    android 30 下拉列表框:ArrayAdapter和Spinner.
    android 29 ArrarAdapter数组适配器
  • 原文地址:https://www.cnblogs.com/thmyl/p/8177534.html
Copyright © 2011-2022 走看看