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 }
原文地址:https://www.cnblogs.com/drizzly/p/7712780.html