Codeforces Round #344 (Div. 2) 乱搞+单调栈+kmp

来源:互联网 发布:宏观数据库 编辑:程序博客网 时间:2024/05/16 04:53

先写一下总结

突然有兴致去打CF…以前好像就打过一次,那次还没认真打…
英语能力有待提升,16分钟敲完前两题你猜我时间花在哪了?

明明C题离正解只有一步之遥了,但就是没想到可以划分出各个区间…智商捉急啊QAQ
D题的kmp明明考场上就get正解了,最后竟然败在了变量名和longlong上!为什么对拍没拍出错!以后还是先静态查错吧QAQ
E题只能说看懂题了,不太会搞的样子…

总之以后需要:积累考试经验,找到考试感觉,打完代码先用脑子检查一遍,思维题要大胆去想(cai)。CF只有俩小时确实时间也不太够…

虽然没我想象的那么好,不过好歹说是涨rating了,就这样吧。


A题

SB题

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int SZ = 1000010;int a[SZ],b[SZ];int main(){    int n;    scanf("%d",&n);    int ans1 = 0,ans2 = 0;    for(int i = 1;i <= n;i ++)    {        scanf("%d",&a[i]);        ans1 |= a[i];    }    for(int i = 1;i <= n;i ++)    {        scanf("%d",&b[i]);        ans2 |= b[i];    }    printf("%d\n",ans1 + ans2);    return 0;}

B题

SB题

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int SZ = 1000010;struct haha{    int id,x;}r[SZ],c[SZ];int main(){    int n,m,k;    scanf("%d%d%d",&n,&m,&k);    for(int i = 1;i <= k;i ++)    {        int k,x,a;        scanf("%d%d%d",&k,&x,&a);        if(k == 1)            r[x] = (haha){i,a};        else            c[x] = (haha){i,a};    }    for(int i = 1;i <= n;i ++)    {        for(int j = 1;j <= m;j ++)        {            if(r[i].id == 0 && c[j].id == 0) printf("0 ");            else if(r[i].id > c[j].id) printf("%d ",r[i].x);            else printf("%d ",c[j].x);        }        puts("");    }    return 0;}

C题

给一个序列,m次操作,每次形如:把[1,ri]按升序/降序排列。求最终序列。

容易发现,若存在一个ri>rj,i>j则j操作是无用的,所以可以先用单调栈维护一个ri单减的操作序列,只有这些操作有用。

然后把新的操作放到一个操作序列里,满足ri>ri+1

然后对于每个区间[ri+1+1,ri],只有第i次操作对它有贡献。若第i次操作是升序,则ri=max1,ri1=max2...ri+1+1=maxx,其中maxi表示未被排序的第i大数。

这样就明确了:先处理出来新的操作序列,然后对于每两个操作序列之间的区间,依次放入最大值、次大值…或依次放入最小值、次小值…,可以通过对原数组排序后得到,具体看代码

挺好的一个乱搞题

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int SZ = 1000010;struct haha{    int r,opt;}S[SZ];int top = 0;bool cmp1(int a,int b) { return a < b; }bool cmp2(int a,int b) { return a > b; }int num[SZ],tmp[SZ];int main(){    int n,m;    scanf("%d%d",&n,&m);     for(int i = 1;i <= n;i ++)        scanf("%d",&num[i]),tmp[i] = num[i];    for(int i = 1;i <= m;i ++)    {        int opt,r;        scanf("%d%d",&opt,&r);        while(top && r >= S[top].r) top --;        S[++ top] = (haha){r,opt};    }    sort(tmp + 1,tmp + S[1].r + 1,cmp1);    S[top + 1].r = 0;    int ll = 0,rr = S[1].r + 1;//  puts("");    for(int i = 1;i <= top;i ++)    {        int r = S[i].r,opt = S[i].opt,r1 = S[i + 1].r + 1;    //  cout<<r1<<" "<<r<<" "<<opt<<endl;        for(int j = r;j >= r1;j --)            if(opt == 1)                num[j] = tmp[-- rr];            else                num[j] = tmp[++ ll];    //for(int i = 1;i <= n;i ++)    printf("%d ",num[i]); puts("");    }    for(int i = 1;i <= n;i ++)  printf("%d ",num[i]);    return 0;}/*5 55 4 3 2 11 52 41 32 21 1*/

D题

求B串在A串中出现多少次,其中字符串是这样给定的:n/m组lici表示当前位置有连续lici。n和m是20万,li是一百万。

SBkmp,打错变量名和没开longlong毁一生QAQ

先把输入中相邻两个字母相同的合并。

然后,若B串在A串中出现,当且仅当B[1,m-2]和A[i,j]完全匹配(字母和数字完全一样);B[0]的字母和A[i-1]一样,B[0]的数字小于等于A[i-1]的数字;B[m-1]的字母和A[j+1]一样,B[m-1]的数字小于等于A[j+1]的数字。

说白了就是B串去掉头和尾然后做kmp,统计答案的时候特判一下头和尾是否合法就行了。对于m=1和m=2的情况单独处理。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const int SZ = 1000010;struct haha{    LL d;    char c;}aa[SZ],bb[SZ],a[SZ],b[SZ],tmp[SZ];bool operator != (haha a,haha b){    return a.d != b.d || a.c != b.c;}bool operator == (haha a,haha b){    return a.d == b.d && a.c == b.c;}int n,m;int nxt[SZ];void getnxt(haha a[],int n){    nxt[0] = nxt[1] = 0;    for(int i = 1;i < n;i ++)    {        int j = nxt[i];        while(j && a[i] != a[j]) j = nxt[j];        nxt[i + 1] = a[i] == a[j] ? j + 1 : 0;    }}LL kmp(haha a[],haha b[],haha c[]){    getnxt(a,m - 2);    LL ans = 0,len = m - 2;    for(int i = 0,j = 0;i < n;i ++)    {        while(j && b[i] != a[j]) j = nxt[j];        if(b[i] == a[j]) j ++;        if(j == len)        {//          printf("%d %d\n",i,j);//          printf("%c %c %c %c\n",c[0].c,b[i - len].c,c[m - 1].c,b[i + 1].c);            if(j - len >= 0)            {                if(c[0].c == b[i - len].c && c[m - 1].c == b[i + 1].c)                    if(c[0].d <= b[i - len].d && c[m - 1].d <= b[i + 1].d)                        ans ++;            }        }    }    return ans;}void change(haha a[],haha aa[],int &n,int n1){    for(int i = 0;i < n1;i ++)    {        a[n] = aa[i];        while(i < n1 - 1 && a[n].c == aa[i + 1].c)        {            a[n].d += aa[i + 1].d;            i ++;         }        n ++;    }}int main(){//  freopen("in.txt","r",stdin);    //  freopen("out.txt","w",stdout);          int n1,m1;    scanf("%d%d",&n1,&m1);    for(int i = 0;i < n1;i ++)        scanf("%I64d-%c",&aa[i].d,&aa[i].c);    for(int i = 0;i < m1;i ++)        scanf("%I64d-%c",&bb[i].d,&bb[i].c);    change(a,aa,n,n1);    change(b,bb,m,m1);/*  for(int i = 0;i < n;i ++)        printf("%d-%c ",a[i].d,a[i].c); puts("");    for(int i = 0;i < m;i ++)        printf("%d-%c ",b[i].d,b[i].c); puts("");*/    if(m == 1)    {        LL ans = 0;        for(int i = 0;i < n;i ++)        {            if(a[i].c == b[0].c && a[i].d >= b[0].d)            {                ans += a[i].d - b[0].d + 1;            //  printf("%d %d\n",a[i].d,b[0].d);            }        }        printf("%I64d",ans);    }    else if(m == 2)    {        LL ans = 0;        for(int i = 0;i < n - 1;i ++)        {            if(a[i].c == b[0].c && a[i + 1].c == b[1].c)            {                if(a[i].d >= b[0].d && a[i + 1].d >= b[1].d)                    ans ++;            }        }        printf("%I64d",ans);                }    else    {        for(int i = 1;i < m - 1;i ++)            tmp[i - 1] = b[i];        printf("%I64d",kmp(tmp,a,b));    }    return 0;}/*6 33-a 4-a 5-b 3-a 2-a 1-a3-a 4-a 5-b*/

E题

弃疗,丢官方题解。
(好像要凸壳什么高端的东西才不知道呢哼)

0 0
原创粉丝点击