zoukankan      html  css  js  c++  java
  • 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串预处理,为了使之后便于比较(即将s和t划分为若干个极长段,满足每段以字母开头且段内只有一种字母。)

    我们把几个相同的字符(去掉*后的)这么表示,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]的前缀和(为了计算答案)

    由于我们要从能买的起的最贵的开始买,我们先二分找出能买的最贵的物品i,然后再二分找出能买得起的连续一段物品i~j。然后为了提高效率,看看j+1这个物品能买多少件,然后尽可能买,扣除相应的钱,继续循环,直到任何一件东西都买不起为止

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    long long sum[100100],sumx[100100];
    struct xxx{
        long long v,x;
    }d[100100];
    int search1(int l,int r,long long y)
    {
        while(l<r)
        {
            int mid=(l+r)/2;
            if(d[mid].v<=y)r=mid;
            else l=mid+1;
        }
        return l;
    }
    int search2(int l,int r,long long y,int last)
    {
        while(l<r)
        {
            int mid=(l+r)/2;
            if(sum[mid]-sum[last]>y)r=mid;
            else l=mid+1;
        }
        return l-1;
    }
    bool cmp(xxx a,xxx b){return a.v>b.v;}
    int main()
    {
    //    freopen("shop.in","r",stdin);freopen("shop.out","w",stdout);
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld%lld",&d[i].v,&d[i].x);
        sort(d+1,d+n+1,cmp);
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+d[i].v*d[i].x,sumx[i]=sumx[i-1]+d[i].x;
        for(int i=1;i<=m;i++)
        {
            long long y;scanf("%lld",&y);
            long long ans=0;
            while(1)
            {
                int ii=search1(1,n+1,y);int jj=search2(ii,n+1,y,ii-1);//cout<<ii<<" "<<jj<<endl;
                if(jj>=ii){ans+=sumx[jj]-sumx[ii-1];y-=sum[jj]-sum[ii-1];}
                if(jj==n)break;
                ans+=(y/d[++jj].v);y=y%d[jj].v;//cout<<y<<"@@"<<ans<<endl;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SQLServer2005删除log文件和清空日志的方案
    使用sql语句创建修改SQL Server标识列(即自动增长列)
    C# 使用ffmpeg.exe进行音频转换完整demo-asp.net转换代码
    web页面如何播放amr的音频文件
    IIS7.5 伪静态 脚本映射 配置方法
    多表数据连接 Left join
    .NET 开发快捷键大全
    微信开发-ACCESS TOKEN 过期失效解决方案
    HTML5常用的方法
    IIS 7.0 部署MVC
  • 原文地址:https://www.cnblogs.com/lher/p/7718780.html
Copyright © 2011-2022 走看看