Codeforces #299 div1

2015-06-10 17:06:06

传送门

总结:挺久以前开的 vp,正赛没做。。

 

A题:数学、二分

  题意:给出一个序列 A,A+B,A+2B,...,A+nB

  每次询问会给出 l,t,m,意思是从序列中选取一段 A+(l-1)B,...,A + (r-1)B,每次你可以选择不同的最多 m 个数使他们都减1,最多执行 t 次,问最大的 r 值为多少。

  思路:比较明显的二分答案,但是检查的步骤呢?

  需要考虑两点:(1)序列的最大值不能超过 t,这个比较显然。

         (2)序列的和不能超过 m×t

  神奇的是只用考虑以上两点即可。

  简证:(1)如果序列个数小于等于m,显然正确。

  (2)序列个数大于 m,每次取 m 个最大的数让他们减1,最后肯定会剩一堆很小的数,由于 t 大于等于最大值,所以最后必定能减完。

  官方的Tutorial给的是一种类似数学归纳法

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)

typedef long long ll;
typedef pair<int,int> pii;
const int INF = (1 << 30) - 1;

int A,B,n;
int l,t,m;
ll st;

bool Check(ll r){
    //l -> r
    ll R = (ll)A + (ll)(r - 1) * B;
    if(t < R) return false;
    if((st + R) * (r - l + 1) / 2 > (ll)t * m) return false;
    return true;
}

int main(){
    scanf("%d%d%d",&A,&B,&n);
    REP(i,n){
        scanf("%d%d%d",&l,&t,&m);
        st = (ll)A + (ll)(l - 1) * B;
        ll sum = (ll)t * m;
        ll top = l + sum / A;
        ll L = l,R = top;
        while(L < R){
            ll mid = getmid(L,R);
            if(Check(mid)) L = mid + 1;
            else R = mid;
        }
        if(L <= l) printf("-1\n");
        else printf("%I64d\n",L - 1);
    }
    return 0;
}
View Code

 

B题:扩展KMP

  题意:给出一个子串,和若干个其在大串中的匹配起点,问你有多少种符合条件的大串。如果不存在这种大串,输出-1

  思路:从小到大逐对考虑匹配起点,如果两个点的差距 >= 子串的长度,那么 distance - length 个位置的字母是26个字母随便放的,26的幂可以用快速幂。

     如果两个点的距离 < 子串的长度,那么就要考虑两个子串重叠部分是否一致,这就是后缀是否匹配前缀的问题了,可以用拓展KMP解决。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)

typedef long long ll;
const int MAXN = 1000010;
const ll mod = 1e9 + 7;

int n,m;
char s[MAXN];
int y[MAXN];
int len;
int nxt[MAXN];

void Ex_kmp(){
    int k = 0,j,p,L;
    nxt[0] = len;
    while(k < len - 1 && s[k + 1] == s[k]) k++;
    nxt[1] = k;
    k = 1;
    for(int i = 2; i < len; ++i){
        p = k + nxt[k] - 1,L = nxt[i - k];
        if(i + L > p){
            j = p - i + 1;
            if(j < 0) j = 0;
            while(i + j < len && s[i + j] == s[j]) j++;
            nxt[k = i] = j;
        }
        else nxt[i] = L;
    }
}

ll Q_pow(int v){
    ll res = 1,x = 26LL;
    while(v){
        if(v & 1) res = res * x % mod;
        x = x * x % mod;
        v >>= 1;
    }
    return res;
}

int main(){
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    len = strlen(s);
    Ex_kmp();
    REP(i,m) scanf("%d",&y[i]);
    if(y[m - 1] + len - 1 > n){
        printf("0\n");
        return 0;
    }
    ll ans = m == 0 ? Q_pow(n) : Q_pow(y[0] - 1) * Q_pow(n - y[m - 1] - len + 1) % mod;
    FOR(i,1,m - 1){
        int d = y[i] - y[i - 1];
        if(d >= len) ans = ans * Q_pow(d - len) % mod;
        else if(nxt[d] < len - d){
            ans = 0;
            break;
        }
    }
    printf("%I64d\n",ans);
    return 0;
}
View Code

 

posted @ 2015-06-10 17:40  Naturain  阅读(121)  评论(0编辑  收藏  举报