zoukankan      html  css  js  c++  java
  • 10.22 AHSOFNU 校内模拟

    字符串(string)

    【题目描述】

           给定两个字符串s,t,其中s只包含小写字母以及*,t只包含小写字母。你可以进行任意多次操作,每次选择s中的一个*,将它修改为任意多个(可以是0个)它的前一个字符。询问是否能将s修改为t。

    【输入描述】

           第一行输入一个整数T,为数据组数。

           每组数据两行,第一行一个字符串s,第二行一个字符串t。

    【输出描述】

           每组数据输出一行,如果能将s修改为t,输出Yes,否则输出No。

    【样例】

    输入

    输出

    2

    a*

    aaaa

    a*

    ab

    Yes

    No

    【数据范围】

    对于字符串a,|a|为a的字符串长度。

    对于20%的数据,|s|,|t|<=7。

    对于60%的数据,|s|,|t|<=300。

    对于100%的数据,T<=100,|s|,|t|<=30000。

    Solution:

      由于一个'*'和多个'*'用法相同,我们可以理解为a*(a*****)和a或者aaaaa....本质上相同。

      发现这个性质后我们可以把s和t分成若干段,每段以字母开头且每段中仅含有一个字母。

      然后对于s中的每一段,如果存在'*',那么它就可以变成字母个数>=本段字母段。

      这个做法是O(T(s+t))。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 using namespace std;
     6 int T;
     7 char s[30010]={0},t[30010]={0};
     8 int main(){
     9     freopen("string.in","r",stdin);
    10     freopen("string.out","w",stdout);
    11     int i=1,j=1,x=1,y=1;
    12     scanf("%d",&T);
    13     while(T--){
    14         scanf("%s",s+1);scanf("%s",t+1);
    15         int lens=strlen(s+1);int lent=strlen(t+1);
    16         i=1,j=1,x=1,y=1;
    17         int flag=1;
    18         while(i<=lens&&j<=lent){
    19             int sum=0;flag=1;
    20             if(s[x]!=t[y]) {
    21                 flag=0;
    22                 printf("No
    ");
    23                 break;
    24             }
    25             while(s[x]==s[i]||s[i]=='*'){
    26                 i++;
    27                 if(s[i]=='*') sum++;
    28             }
    29             while(t[y]==t[j]) j++;
    30             int t1=i-x-sum;
    31             int t2=j-y;
    32             x=i;y=j;
    33             if((t1==t2&&sum==0)||(sum>0&&t1<=t2)) continue;
    34             else{   
    35                 printf("No
    ");
    36                 flag=0;
    37                 break;
    38             }
    39         }
    40         if(flag==1){
    41             if(i<=lens||j<=lent) printf("No
    ");
    42             else printf("Yes
    ");
    43         }
    44     }
    45     return 0;
    46 }

    //std 写的玄学好看

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<stdlib.h>
     4 #include<string.h>
     5 #include<math.h>
     6 #include<algorithm>
     7 using namespace std;
     8 int T,n,m;
     9 char s[30010],t[30010];
    10 int main(){
    11     freopen("string.in","r",stdin);
    12     freopen("string.out","w",stdout);
    13     int i,j,k,l,u;
    14     scanf("%d",&T);
    15     while(T--){
    16        scanf("%s%s",&s,&t);
    17        n=strlen(s);m=strlen(t);
    18        for(i=j=0;i<n;i=k,j=l){
    19           u=0;
    20           for(k=i;k<n && (s[k]=='*' || s[k]==s[i]);k++) if(s[k]=='*') u++;
    21           for(l=j;l<m && t[l]==t[j];l++);
    22           if(!(s[i]==t[j] && k-i-u<=l-j && (u || k-i==l-j))) break;
    23          }
    24        if(i<n || j<m) printf("No
    ");
    25        else printf("Yes
    ");
    26       }
    27     return 0;
    28 }
    std

    或(or)

    【题目描述】

           你需要构造一个长度为n的数列X,当中的数字范围从0到2^30-1。除此之外你需要满足m个条件,第i个条件为X[li]|X[li+1]|……|X[ri]=pi。|为按位或运算。

    【输入描述】

           第一行输入两个整数n,m

           接下来的m行每行输入三个整数li,ri,pi

    【输出描述】

    如果存在这样的序列,第一行输出Yes,否则输出No。

    如果存在这样的序列,第二行输出n个数,为数列X。

    【样例】

    输入

    输出

    2 1

    1 2 1

    Yes

    1 1

    【数据范围】

    对于30%的数据,n,m<=1000。

    对于另外30%的数据,pi<=1。

    对于100%的数据,n,m<=100000,1<=li<=ri<=n,0<=pi<2^30。

    Solution:

      中间30%:对于每个条件,如果pi=0,那么x[li]…x[ri]显然都为0,否则至少要有一个1。

        由于我们只需要构造出一组可行解,那么我们可以把没被要求为0的x[i]都设为1,然后判断是否满足每个条件即可。

        区间赋值和区间询问可以用线段树维护。

        时间复杂度O(mlogn)

      100%:由于或运算每一位是相互独立的,因此可以将上述做法推广到pi>1的情况。

        初始时x[i]=2^30-1,对于每个条件,将x[li]…x[ri]中pi=0的位修改为0,最后判断是否满足条件。同样使用线段树维护。

        时间复杂度O(mlogn)

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<stdlib.h>
     4 #include<string.h>
     5 #include<math.h>
     6 #include<algorithm>
     7 using namespace std;
     8 int n,m,f[400010],l[100010],r[100010],x[100010],p;
     9 inline void add(int i,int j,int k,int l,int r,int x)
    10 {
    11     if(l<=j && k<=r)
    12       f[i]|=x;
    13     else
    14       {
    15        if(l<=(j+k>>1))
    16          add(i<<1,j,j+k>>1,l,r,x);
    17        if(r>(j+k>>1))
    18          add(i<<1|1,(j+k>>1)+1,k,l,r,x);
    19       }
    20 }
    21 inline int sum(int i,int j,int k,int l,int r)
    22 {
    23     if(l<=j && k<=r)
    24       return f[i];
    25     else
    26       {
    27        int p=(1<<30)-1;
    28        if(l<=(j+k>>1))
    29          p&=sum(i<<1,j,j+k>>1,l,r);
    30        if(r>(j+k>>1))
    31          p&=sum(i<<1|1,(j+k>>1)+1,k,l,r);
    32        return p;
    33       }
    34 }
    35 int main()
    36 {
    37     freopen("or.in","r",stdin);
    38     freopen("or.out","w",stdout); 
    39     int i,j,k;
    40     scanf("%d%d",&n,&m);
    41     for(p=1;p<n;p<<=1);
    42     for(i=1;i<=m;i++)
    43       {
    44        scanf("%d%d%d",&l[i],&r[i],&x[i]);
    45        x[i]^=(1<<30)-1;
    46        add(1,1,p,l[i],r[i],x[i]);
    47       }
    48     for(i=1;i<p;i++)
    49       {
    50        f[i<<1]|=f[i];
    51        f[i<<1|1]|=f[i];
    52       }
    53     for(i=p-1;i>0;i--)
    54       f[i]=f[i<<1]&f[i<<1|1];
    55     for(i=1;i<=m;i++)
    56       if(sum(1,1,p,l[i],r[i])!=x[i])
    57         break;
    58     if(i<=m)
    59       printf("No
    ");
    60     else
    61       {
    62        printf("Yes
    ");
    63        for(i=1;i<=n;i++)
    64          printf("%d ",f[p+i-1]^(1<<30)-1);
    65        printf("
    ");
    66       }
    67     return 0;
    68 }
    std

    商店(shop)

    【题目描述】

           在m天内,每天都有n种商品,第i种的物品的价格为vi,此物品每天最多只能购买xi个。第i天你有wi的钱,你会不停购买能买得起的最贵的物品。你需要求出每天会购买多少个商品。每一天的钱如果有剩,那么将会被Ditoly拿走,而不会被留到第二天用。

    【输入描述】

    第一行两个整数n,m。

    接下来n行每行两个整数vi,xi。接下来m行每行一个整数wi。

    【输出描述】

           m行每行一个整数,第i行表示第i天购买的物品数量。

    【样例】

    输入

    输出

    3 3

    1 1

    2 2

    3 3

    5

    10

    15

    2

    4

    6

    【数据范围】

    对于20%的数据,n,m<=1000。

    对于另外40%的数据,xi=1。

    对于100%的数据,n,m<=100000,1<=vi<=10^9,1<=xi<=10000,0<=wi<=10^18。

    Solution:

      二分。

         我们先对物品价格排序,然后二分出能买最贵的一段,然后前缀和相减即可。 O(nlognlogw)

    //官方:

    20%:按题意暴力模拟即可。

      时间复杂度O(nm)。

    中间40%:首先对物品按价格排序并预处理出前缀和。对于每次询问,我们二分找出能买得起的最贵的物品i,再二分找出能买得起的连续一段物品i~j。

      由于买下i~j后买不起j+1,并且j+1的价格不大于i的价格,因此至少花费了一半的钱。那么我们只需要二分logw次即可。

      时间复杂度O(nlognlogw)。

    100%:不难发现上述做法可以推广到每种物品个数>1的情况,也就是二分能全部买下的一段,再求一下下一个物品能买多少个。

      时间复杂度O(nlognlogw)。

        

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define MAXN 100005
     4 #define LL long long
     5 using namespace std;
     6 int n,m,w[MAXN];
     7 int l,r;
     8 int i,cnt,summ=0;
     9 LL mon=0,monn=0;
    10 LL sum[MAXN];
    11 struct data{
    12     int v,x;
    13 }a[MAXN];
    14 void erfen_l(){
    15     for(l=1,r=i;l<r;){
    16         int mid=(l+r+1)>>1;
    17         if(mon>=a[mid].v) l=mid;
    18         else r=mid-1;
    19     }
    20 } 
    21 void erfen_r(){
    22     for(l=1,r=i;l<r;){
    23         int mid=(l+r)>>1;
    24         if(mon>=sum[i]-sum[mid]) r=mid;
    25         else l=mid+1;
    26     }
    27 }
    28 bool cmp(data a,data b){return a.v<b.v;}
    29 int main(){
    30     freopen("shop.in","r",stdin);
    31     freopen("shop.out","w",stdout);
    32     scanf("%d%d",&n,&m);
    33     for(i=1;i<=n;i++) scanf("%d%d",&a[i].v,&a[i].x);
    34     sort(a+1,a+n+1,cmp);
    35     for(i=1;i<=n;i++){
    36         sum[i]=sum[i-1]+(LL)a[i].v*a[i].x;
    37         w[i]=w[i-1]+a[i].x;
    38     }
    39     while(m--){
    40         scanf("%lld",&mon);
    41         for(i=n,cnt=0;i>0&&mon>=a[1].v;){
    42             erfen_l();
    43             i=l;
    44             if(mon>=sum[i]) {cnt+=w[i];break;}
    45             erfen_r();
    46             mon-=sum[i]-sum[l]; //summ=sum[i]-sum[l];
    47             cnt+=w[i]-w[l]+mon/a[l].v;//monn=mon/a[l].v;
    48             mon%=a[l].v;
    49             i=l-1;
    50         }
    51         printf("%d
    ",cnt);
    52     }
    53     return 0;
    54 }
  • 相关阅读:
    集群任务管理系统SGE的简明教程
    三代全长转录组测序和组装
    quota
    基因组转座元件
    单倍体
    什么是寒武纪、志留纪、泥盆纪、白垩纪
    对组装之后的三代基因组进行polish
    使用 PhyML 构建进化树
    PAML软件中的mcmctree命令估算物种分歧时间
    OrthoMCL及orthofinder 两种软件进行聚类分析
  • 原文地址:https://www.cnblogs.com/drizzly/p/7712780.html
Copyright © 2011-2022 走看看