Codeforces #299 Div 1 简要题解

A. Tavas and Karafs(536A)

题目链接

http://codeforces.com/contest/536/problem/A

题目大意

给你一个首项为 A ,公差为B的等差序列( h1=A,hi=hi1+B )
n 次询问(L,t,m),即在序列中找出一个最大的 R ,使得最多进行t次操作就能将 hL...hR 全部变为0,定义一次操作是在序列中选择不超过 m 个元素,并将它们全部减1

思路

首先给出一个引理:一个有限的等差序列P1....Pn,其中所有的元素均非负,若 max{P1,P2...Pn}t iPimt ,则我们称这个等差序列可以在 t 次操作内全部变为0,简称这个等差序列是完美的,该状态简写为一个二元组(m,t)

证明:
考虑两种情况。
1、该等差序列中非零数字个数不到 m

我们可以每次操作把等差序列里所有的非零数字全部减1
由于iPimt,显然这个等差序列是完美的

2、该等差序列中非零数字个数大于等于 m

我们首先找出这个序列里所有的Pi=t

满足上述条件的 Pi 显然不超过 m 个,因为若满足条件的Pi超过 m 个,那么就会使得最终的iPi>mt,与之前预设条件矛盾

然后将这些 Pi 全部减去1,假设共有 x 个符合条件的P(xm),那么此时在这个新序列里, max{P1,P2...Pn}t1 iPi=iPixmtx ,问题转换成 (m,t1) ,如此反复,便会到情况1的状态,因此当前的序列也是完美的

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

LL A,B;
int n;

LL getKth(int x)
{
    return A+(x-1)*B;
}

int main()
{
    scanf("%I64d%I64d%d",&A,&B,&n);
    for(int i=1;i<=n;i++)
    {
        int L,t,m;
        scanf("%d%d%d",&L,&t,&m);
        LL fL=getKth(L);
        int lowerBound=L,upperBound=1100000,ans=-1;
        while(lowerBound<=upperBound)
        {
            int mid=(lowerBound+upperBound)>>1;
            LL fM=getKth(mid);
            LL sum=(fL+fM)*(mid-L+1)/2;
            if(fM<=t&&sum<=(LL)m*t)
            {
                ans=mid;
                lowerBound=mid+1;
            }
            else upperBound=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

B. Tavas and Malekas(536B)

题目链接

http://codeforces.com/contest/536/problem/B

题目大意

给你一个字符串 P ,要你构造一个长度为n的字符串 S ,使得以给定的m个下标作开头的后缀里,字符串 P 都是其中的前缀。

思路

显然要先把m P 串插入到给定的m个位置上去,若 m P串不相互冲突(在 S 串同样的位置上两个P串的字母都是相同的),假设插入了所有的字符串后,还有 t 个空位置,那么就能构造出26t个不同的长度为 n 的字符串。

那么如何判断m P 串里是否存在某些对P串相互冲突呢?我们可以 O(n) 扫一遍每个 P 串,判断是否有与其相邻的P串,和它相交的那部分存在冲突,这个可以通过hash来判,为了防止被卡hash,建议使用双hash。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 2100000
#define MOD1 1000000007
#define MOD2 1000000009
#define BASE 233

using namespace std;

typedef long long int LL;

int n,m;
LL hash1[MAXN],pow1[MAXN]; //pow[i]=BASE^i
LL hash2[MAXN],pow2[MAXN]; //pow[i]=BASE^i
char P[MAXN];

LL gethash1(int L,int R)
{
    return ((hash1[R]-hash1[L-1]*pow1[R-L+1]%MOD1)%MOD1+MOD1)%MOD1;
}

LL gethash2(int L,int R)
{
    return ((hash2[R]-hash2[L-1]*pow2[R-L+1]%MOD2)%MOD2+MOD2)%MOD2;
}

bool mark[MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",P+1);
    int len=strlen(P+1);
    int freeNum=0;
    pow1[0]=1;
    for(int i=1;i<=n;i++) pow1[i]=pow1[i-1]*BASE%MOD1;
    for(int i=1;i<=n;i++) hash1[i]=(hash1[i-1]*BASE%MOD1+P[i]-'a'+1)%MOD1;

    pow2[0]=1;
    for(int i=1;i<=n;i++) pow2[i]=pow2[i-1]*BASE%MOD2;
    for(int i=1;i<=n;i++) hash2[i]=(hash2[i-1]*BASE%MOD2+P[i]-'a'+1)%MOD2;

    int pre=0;
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        mark[x]=true;
    }
    for(int i=1;i<=n;i++)
    {
        if(mark[i])
        {
            if(pre&&pre+len>i)
            {
                int tmp=pre+len-i;
                if(gethash1(1,tmp)!=gethash1(len-tmp+1,len)||gethash2(1,tmp)!=gethash2(len-tmp+1,len))
                {
                    printf("0\n");
                    return 0;
                }
            }
            pre=i;
        }
        if(!pre||pre+len<=i) freeNum++;
    }
    LL ans=1;
    for(int i=1;i<=freeNum;i++)
        ans=(ans*26)%MOD1;
    printf("%I64d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值