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

先写一下总结

突然有兴致去打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 5
5 4 3 2 1
1 5
2 4
1 3
2 2
1 1


*/

D题

求B串在A串中出现多少次,其中字符串是这样给定的:n/m组 lici 表示当前位置有连续 li ci 。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 3
3-a 4-a 5-b 3-a 2-a 1-a
3-a 4-a 5-b
*/

E题

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值