contest hunter5702(倍增dp)

题目描述
将S = [s,n]定义为由n个连接的字符串组成的字符串S. 例如,[“abc”,3] =“abcabcabc”。
另一方面,如果我们可以从s2中删除某些字符使其变为s1,我们定义字符串s1可以从字符串s2获得。 例如,“abc”可以根据我们的定义从“abdbec”获得,但不能从“acbbe”获得。
给你两个非空字符串s1和s2(每个最多100个字符)和两个整数0≤n1≤106和1≤n2≤106。现在考虑字符串S1和S2,其中S1 = [s1,n1] 和S2 = [s2,n2]。 找到最大整数M,使得可以从S1获得[S2,M]。
样例数据
input
s1=”acb”, n1=4
s2=”ab”, n2=2
output
2
数据规模与约定
时间限制:1s1s
空间限制:256MB


做法非常巧妙
我们先求出第一个串在第二个串最多可以出现的次数 m
这个怎么求呢?
我们可以对 m 拆分二进制
然后就可以记 f i , j 表示从第二个串第 i 个位置开始匹配,匹配 2 j 个串一需要的位置
f i , 0 可以暴力求出

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define fr first
#define se second
#define file(k) memset(k,0,sizeof(k))
#define ll long long
char s1[101] , s2[101];
int n1 , n2 , len1 , len2;
int dp[110][30];
void work()
{
    len1 = strlen(s1);len2 = strlen(s2);memset(dp,0,sizeof(dp));
    rep(st,0,len1-1)
    {
        int i = 0 , j = st , sum = 0;
        int det = 0;
        while(i < len2)
        {
            if(det > len1) {printf("0\n");return;}
            if(s2[i] == s1[j]) i++,j++,sum++,det = 0;
            else j++,sum++,det++;
            j %= len1;
        }
        dp[st][0] = sum;
    }
    for(int j = 1;(1<<j) <= n1*len1/len2;++j)
        rep(i,0,len1) 
            dp[i][j] = dp[i][j-1] + dp[ (dp[i][j-1] + i)%len1 ][j-1];
    int x = len1*n1;
    int now = 0;
    int ans = 0;
    repp(j,27,0)
        if(dp[now][j] != 0 && x - dp[now][j] >= 0)
        {
            x -= dp[now][j];
            now += dp[now][j];
            now %= len1;
            ans += 1<<j;
        }
    ans /= n2;
    printf("%d\n",ans);
}
int main()
{
    while(scanf("%s%d%s%d",s2,&n2,s1,&n1) == 4)  work();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/82532040