BestCoder No.11 总结

来源:互联网 发布:java log4j 日志格式 编辑:程序博客网 时间:2024/06/06 20:53

这算是我们集训队第一次集体做吧,主要写给其他人看的。

A题:

没啥说的,判断所给的x,y是不是分别是n与m的二分之一即可。

代码:

#include<cstdio>#include<cstring>#include<iostream>using namespace std;int n,m,x,y;int main(){    while(scanf("%d%d%d%d",&n,&m,&x,&y)!=EOF)    {        if(x*2==n&&y*2==m)            printf("YES\n");        else            printf("NO\n");    }    return 0;}

B题:

这个题要求求出所给一些数能够组成的最大的,并且没有前导0,并且是奇数的数。

思路:

1、首先我们应该从小到大排序(因为所求最大,贪心),然后将最后一个与最小的奇数进行交换(如果是最后一个是奇数的话没有影响)

2、在做第一个处理以后,如果找不到这样的奇数那么输出-1,对于交换后的数我们需要对除最后一个外的所有数进行排序,因为交换后可能不满足大小排序了,想一想?

3、再次排序后还需要判断下最大的是否为0(除去前导0),若最大的为0,则为-1,否则从大到小输出即可。

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn=110;int n,a[maxn];int main(){    while(scanf("%d",&n)!=EOF)    {        for(int i=0;i<n;i++)            scanf("%d",&a[i]);        sort(a,a+n);        int pos=-1;        for(int i=0;i<n;i++)            if(a[i]&1)            {                pos=i;                break;            }        if(pos==-1)        {            printf("-1\n");            continue;        }        swap(a[pos],a[0]);        sort(a+1,a+n);        if(a[n-1]==0)        {            printf("-1\n");            continue;        }        for(int i=n-1;i>=0;i--)            printf("%d",a[i]);        printf("\n");    }    return 0;}

C题:

这个题要求求出出现字符不超过k次的子串个数(不用去重):

思路:

1、对于一个长度为n的字符串它的子串个数很明显是1+2+....+n的和。

2、有了1的结论,那么我们可以预处理长度为n的子串为多少。然后我们设置前后points,保证所指向的区间的字符重复数不超过k,那么可以直接算出这个区间的所有子串,然后通过移动前后points调整到下一个区间。

3、经过2计算的话我们会算了重复的子串,设前后points分别为pre和last,那么当pre移动后,last移动向下一个合法区间设为last2,那么计算的时候很明显pre->last(上次的last)是重复计算了的,如果我们按照pre->last2区间计算子串的话,那么我们只需要把这个重复的减去即可。

代码:

#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int maxn=1e5+100;long long num[maxn];char str[maxn];int cnt[30],k;void Init(){    num[1]=1;    for(int i=2;i<=1e5;i++)        num[i]=num[i-1]+i;}int main(){    Init();    int T;    scanf("%d",&T);    while(T--)    {        scanf("%s",str);        scanf("%d",&k);        memset(cnt,0,sizeof(cnt));        int len=strlen(str);        int pre=0,last=0,prlast=0;        long long ans=0;        while(last<len)        {            prlast=last;            while(last<len)            {                if(cnt[str[last]-'a']+1>k)                    break;                cnt[str[last++]-'a']++;            }            ans+=num[last-pre]-num[prlast-pre];            while(pre<last&&cnt[str[last]-'a']>=k)            {                cnt[str[pre]-'a']--;                pre++;            }        }        printf("%I64d\n",ans);    }    return 0;}

D题:

这个很明显是个单点更新区间查询的题,也就说给你一些初始值,然后每次可以改变其中的一个值,查询的时候需要查询[L,R]中第D位数值为P的个数。

思路:

1、如果没有求某位的数值是多少或者数据量稍小点,那么直接用线段树或者树状数组可以解决。(现在所需要数组的大小为1e7,稍大),如果直接写线段树的话应该会超时。那么我们可以考虑分治思想,将10位分别处理,每次处理就转换成单调更新、区间查询了(典型的树状数组)。

2、想到1的话就需要离线处理,将所有的更新和查询保存下来(注意保存先后关系,即每次查询操作一定要保证之前的更新全部完成),我的处理方法是把每位的查询保存下来,然后依次枚举每一位,注意查询的时候更新之前所有的操作,然后就交给二维树状数组就行了,t[x][y]:x表示的是位置,y表示的是该位置数值为y。

代码:

#include<cstdio>#include<cstring>#include<iostream>#include<vector>using namespace std;const int maxn=1e5+100;int n,m,a[maxn],b[maxn],t[maxn][11],ans[maxn];int num[12]={1,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};struct Node{    int l;    int r;    int num;    int nth;    Node(){}    Node(int sl,int sr,int snum,int sth)    {        l=sl;r=sr;num=snum;nth=sth;    }};struct Set{    int pos;    int val;    int nth;    Set(){}    Set(int spos,int sval,int snth)    {        pos=spos;        val=sval;        nth=snth;    }};vector<Node> q[11];vector<Set> s;int lowbit(int x){    return x&(-x);}void Update(int x,int val,int pos){    for(;x<=n;t[x][pos]+=val,x+=lowbit(x));}int Sum(int x,int pos){    int ans=0;    for(;x>0;ans+=t[x][pos],x-=lowbit(x));    return ans;}void Init(){    for(int i=0;i<=10;i++)        q[i].clear();    s.clear();}int main(){    int T;    scanf("%d",&T);    while(T--)    {        Init();        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        for(int i=0;i<m;i++)        {            char op[2];            scanf("%s",op);            if(op[0]=='Q')            {                int l,r,pos,num;                scanf("%d%d%d%d",&l,&r,&pos,&num);                q[pos].push_back(Node(l,r,num,i));            }            else            {                int pos,val;                scanf("%d%d",&pos,&val);                s.push_back(Set(pos,val,i));            }        }        memset(ans,-1,sizeof(ans));        for(int i=1;i<=10;i++)        {            int l=q[i].size(),k=0;            if(l==0)                continue;            memset(t,0,sizeof(t));            for(int j=1;j<=n;j++)            {                Update(j,1,a[j]/num[i]%10);                b[j]=a[j];            }            for(int j=0;j<l;j++)            {                while(k<s.size()&&s[k].nth<q[i][j].nth)                {                    Update(s[k].pos,-1,b[s[k].pos]/num[i]%10);                    Update(s[k].pos,1,s[k].val/num[i]%10);                    b[s[k].pos]=s[k].val;                    k++;                }                ans[q[i][j].nth]=Sum(q[i][j].r,q[i][j].num)-Sum(q[i][j].l-1,q[i][j].num);            }        }        for(int i=0;i<m;i++)            if(ans[i]!=-1)                printf("%d\n",ans[i]);    }    return 0;}




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 不爱学习的小孩怎么办 一年级小孩不爱学习怎么办 小孩不听话不爱学习怎么办 父母犯错我们该怎么办 孩子学习不爱动脑筋怎么办 孩子考试太马虎怎么办 小孩做作业马虎怎么办 同学抄我作业怎么办 别人抄我答案怎么办 学生考试前紧张怎么办 科目一考试紧张怎么办 1年级不认真学习怎么办 学生考试时紧张怎么办 小朋友不写作业怎么办 面对作业多应该怎么办 小学学生作业多怎么办 二年级学生马虎怎么办 孩子做数学题粗心怎么办 小孩拉的屎很粗怎么办 生地会考没及格怎么办 小孩大便特别粗怎么办 孩子拉屎太粗怎么办 地生考d怎么办 突然考的很差怎么办 犯同样的错误怎么办 考研考砸了怎么办 好学生九宫格怎么办 考试时有不会题怎么办 孩子是个滚刀肉怎么办 初中审题不认真怎么办 孩子出错率高怎么办 一年级小孩不认真怎么办 旅游时孩子走失怎么办 小孩抄作业怎么办啊 鼻塞流涕老不好怎么办 二年级学生贪玩怎么办 一年级孩子做题不认真怎么办 纹身之后喝酒啦怎么办 股票爆仓散户怎么办 小学一年级孩子马虎怎么办 一年级孩子考试马虎怎么办