20171022校内训练

Posted lh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20171022校内训练相关的知识,希望对你有一定的参考价值。

字符串(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。

这我也不知道是什么算法了,反正就是随便做,但是就是狗了,究其原因,4个t打成s

首先,我们对于s串预处理,为了使之后便于比较

我们把几个相同的字符(去掉*后的)这么表示,ss[tots]表示该字符,sss[tots]表示该字符出现的次数

对于t串,也进行如上处理,tt[tott]表示该字符,ttt[tott]表示该字符出现的次数

那么*要怎么办呢?我们用数组_s[tots]表示ss[tots]字符是否存在*(即该字符是否能被无限加长)

具体实现就记下上一个搜到的不为*的字符的位置(记字符也是可以的)(记为last),然后把当前字符与last比较,若相等,则sss[tots]++,若不等且该位不是*,则tots++,然后记录下这种字符ss[tots]=s[i],把它的出现次数设为1  sss[tots]=1,把last记为它,若该位是*,则让_s[tots]=1即可(即ss[tots]字符能被无限延长)

若tots!=tott,那么一定无解(相同字符的段数都不相同了,就不可能有解)

否则我们对于ss和tt的每一位匹配,若这一位的字符一样且出现次数相等(或s串出现次数<t串出现次数且s串该字符能被无限延长)则继续下一位,否则无解

注意:数组要清0,strlen的效率是O(len)的,不要放在循环里,在循环开始的时候做一次就好了

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[30101],t[30101];
char ss[30101],tt[30101];int sss[30101],ttt[30101];bool _s[30101];
int main()
{
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%s%s",s,t);memset(sss,0,sizeof(sss));memset(ttt,0,sizeof(ttt));memset(_s,0,sizeof(_s));
        int tots=0,tott=0;
        int now=0,last=30010,lens=strlen(s),lent=strlen(t);s[30010]=&;
        for(int i=0;i<lens;i++)
        {
            if(s[i]==*)_s[tots]=1;
            else if(s[i]==s[last])sss[tots]++;
            else if(s[i]!=s[last]){tots++;sss[tots]=1;ss[tots]=s[i];last=i;}
        }
    //    for(int i=1;i<=tots;i++)cout<<ss[i]<<" "<<sss[i]<<" "<<_s[i]<<endl;
        now=0;last=30010;t[30010]=&;
        for(int i=0;i<lent;i++)
        {
            if(t[i]==t[last])ttt[tott]++;
            else if(t[i]!=t[last]){tott++;ttt[tott]=1;tt[tott]=t[i];last=i;}
        }
    //    for(int i=1;i<=tott;i++)cout<<tt[i]<<" "<<ttt[i]<<endl;
        int x=1,y=1;bool ok=1;
        for(int i=1;i<=min(tots,tott);i++)
        {
            if(ss[i]==tt[i]&&(sss[i]==ttt[i]||sss[i]<=ttt[i]&&_s[i]));
            else {ok=0;break;}
        }
        if(ok==0||tots!=tott)puts("No");else puts("Yes");
    }
    return 0;
}
View Code

 

或(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。

商店(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。

各种二分。其实我也不能保证复杂度,但是是我能想到的最快的算法了。

显然,我们应该先按vi排序,处理出v[i]*x[i]的前缀和(为了计算价钱)和x[i]的前缀和(为了计算答案)

由于我们要从能买的起的最贵的开始买,我们先

以上是关于20171022校内训练的主要内容,如果未能解决你的问题,请参考以下文章

校内训练2019-11-15跳一跳

校内训练2019-11-15逮虾户

校内训练2019-11-15表演

20171129校内训练

「csp校内训练 2019-10-30」解题报告

三中校内训练净化