Acwing 294.计算重复 (倍增优化DP)

题目

定义 conn(s,n) 为 n 个字符串 s 首尾相接形成的字符串,例如:

conn(“abc”,2)=”abcabc”
称字符串 a 能由字符串 b 生成,当且仅当从字符串 b 中删除某些字符后可以得到字符串 a。

例如“abdbec”可以生成“abc”,但是“acbbe”不能生成“abc”。

给定两个字符串 s1 和 s2,以及两个整数 n1 和 n2,求一个最大的整数 m,满足conn(conn(s2,n2),m) 能由 conn(s1,n1) 生成。

输入格式
输入包含多组测试数据。

每组数据由2行组成,第一行包含s2,n2,第二行包含s1,n1。

输出格式
对于每组数据输出一行表示答案m。

数据范围
s1 和 s2 长度不超过100,n1 和 n2 不大于 106。

输入样例:
ab 2
acb 4
acb 1
acb 1
aa 1
aaa 3
baab 1
baba 11
aaaaa 1
aaa 20
输出样例:
2
1
4
7
12

思路

是一道倍增dp,可以匹配的最大字串个数。1e6的数据量并不算小了,那么我们考虑从s1的每个字母尝试去匹配s2,并用数组记录长度,考虑到倍增的思想,所以我们这里记录的都是匹配2的某次方个s2所需长度,然后从倒序枚举2的次方,依次加入,当这个长度大于母串长度就退出,最后的答案是长度对被匹配串的长度相除下取整。

代码实现

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int ,int> PII;
ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
inline int read() {
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f = -1;
        ch=getchar();
    } 
    while('0'<=ch&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }   return x*f;
}

const int maxn=110,M=31;
string s1,s2;
int n1,n2;
ll dp[maxn][M];


int main () {
//    freopen ("data.in","r",stdin);
   while (cin>>s2>>n2>>s1>>n1) {
       int sz=s1.size ();
       
       bool fail=false;
       rev (i,0,sz) {
           int p=i;
           dp[i][0]=0;
           rev (j,0,s2.size ()) {
               int cnt=0;
               while (s1[p]!=s2[j]) {
                   p=(p+1)%sz;
                   cnt++;
                   if (cnt>sz) {
                       fail=true;
                       break;
                   }
               }
               if (fail) break;
               p= (p+1)%sz;
               dp[i][0]+=cnt+1;
           }
           if (fail) break;
       }
       if (fail) {
           cout<<0<<endl;
           continue;
       }        

       rep (j,1,30) 
         rev (i,0,sz) {
             dp[i][j]=dp[i][j-1]+dp[(i+dp[i][j-1])%sz][j-1];
         }

        ll ans=0;
        rev (i,0,sz) {
            ll p=i,t=0;
            per (k,30,0) 
               if (p+dp[p%sz][k]<=sz*n1) {
                   p+=dp[p%sz][k];
                   t+=1<<k;
               }
               ans=max (ans,t);
        }
        cout<<ans/n2<<endl;
   }   

//    fclose (stdin);
   return 0;
}

原文地址:https://www.cnblogs.com/hhlya/p/13473175.html