ABC346F 题解
题意
给出整数
思路
显然,若
现在需要写出check函数,考虑反过来做,对于一个
这样问题就成了求把
这里要注意二分的上界,设
代码
#include<iostream>
#include<vector>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+10;
const int K=26+10;
int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
int n,ls,lt;
char s[N],t[N];
int a[N][K];//a_i 记录s串中第i位到末尾 各个字母出现次数
vector <int> pos[K];//pos_i 记录s串中第i个字母出现的位置
bool check(int x)
{
if(x==0) return true;
int cnt=0,lpos=ls;//cnt表示构成g(T,x)需要的s串个数,lpos表示上一个s串用到了第(lpos-1)位
for(int i=0;i<lt;i++)//构成每个字母
{
int tc=t[i]-'a',ts=x;//需要的字符及数量
if(ts<=a[lpos][tc]) //如果上一个s串中剩余的tc足够
lpos=pos[tc][a[0][tc]-a[lpos][tc]+ts-1]+1;//只需修改使用到的位置
else
{
ts-=a[lpos][tc];//先把上个串用完
cnt+=ts/a[0][tc];//再用完整的若干个串
ts%=a[0][tc];//还需要多少个该字母
if(ts)
{
cnt++;
lpos=pos[tc][ts-1]+1;
}//如果还需要,就多用一个串并记录位置
else lpos=pos[tc][a[0][tc]-1]+1;//否则记录s串中该字母最后一次出现的位置即可
}
}
return cnt<=n;//判断是否合法
}
signed main()
{
n=read();
cin>>s>>t;
ls=strlen(s),lt=strlen(t);
for(int i=ls-1;i>=0;i--)
{
for(int j=0;j<26;j++) a[i][j]=a[i+1][j];
a[i][s[i]-'a']++;
}//倒序处理后缀a数组
for(int i=0;i<lt;i++) if(!a[0][t[i]-'a'])
{
cout<<0;
return 0;
}//这里特判:若t串中有s串没有的字符,则直接输出0
//如果不判的话,在check函数里会除以0寄掉
for(int i=0;i<ls;i++) pos[s[i]-'a'].push_back(i);//正序记录各字母出现位置
int l=0,r=n*ls/lt,ans;//这里二分上界要注意
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}//二分答案
cout<<ans;
return 0;
}