力扣466
定义 str = [s, n]
表示 str
由 n
个字符串 s
连接构成。
- 例如,
str == ["abc", 3] =="abcabcabc"
。
如果可以从 s2
中删除某些字符使其变为 s1
,则称字符串 s1
可以从字符串 s2
获得。
- 例如,根据定义,
s1 = "abc"
可以从s2 = "abdbec"
获得,仅需要删除加粗且用斜体标识的字符。
现在给你两个字符串 s1
和 s2
和两个整数 n1
和 n2
。由此构造得到两个字符串,其中 str1 = [s1, n1]
、str2 = [s2, n2]
。
请你找出一个最大整数 m
,以满足 str = [str2, m]
可以从 str1
获得。
1 <= s1.length, s2.length <= 100
s1
和s2
由小写英文字母组成1 <= n1, n2 <= 106
上题和这题比起来。。
思路不要太清晰了
但是这题也是和上题一样,我看到的第一眼不知道我能够做写什么
因为感觉干什么都会直接T掉
这么看。。倍增我还是太不熟悉了
我不能敏锐的察觉出什么东西能够用倍增算出来,这才会觉得什么都干不了
看来倍增题写少了。。。
等弄完dp就去弄弄倍增吧
我似乎弄错了,我没有考虑到循环这个特征能够省略一些计算
然后倍增优化的状态设计特点是f[i,j]表示从i开始,2^j作为一个限制,或者是要求,有点类似背包的容量,能够干嘛干嘛,然后这个东西是能够累加的,而且是相对固定的一个东西,判断的规则不会受到起始点位置不同的影响
。。限制挺严格的其实
对于这题,就是设f[i][j]表示从str1的i位置开始,最少用几个字符才能合成str2*(2^j)
对于上题,就是设f[i][j]表示从城市i开始,走2^j天能够到达哪个位置
最重要的就是这个东西可以以相加的方式合并答案,然后有一个类似步数的东西在控制位置
模型建不起来。。不知道这一类的题目到底是什么样的,还是要写更多的题目才行
和区间dp的以“最后一次操作”作为划分点的题目一样。。只是会做这几题,还不够。要是做不到那种能够出题的阶段,遇到还是很容易写不出来
上一题的和这一题对应的一个特征是上一题在不同位置的时候,开车的法则是不变的,这一题则是str2总是在循环,配对的法则是没变的,所以这两题倍增的答案都能够相加
想了两天,现在大概是明白了。
主要是看到了这样一道题目https://www.luogu.com.cn/problem/P3147
这题,我看到的第一眼就很像区间dp
但是!它的n,是二十万
这是个n,别说是区间dp了,普通的O(n^2)也无法接受,O(n^3)就是天方夜谭
但是这是可以倍增优化的
这个题目和我之前遇到的一题十分相似,就是poj1390
同样是合并,同样是求一个最大值,这两题做法不一样的根本原因就是,poj1390中对同一段区间的合并先后顺序其实是在影响答案的优劣的
而在这题中,我对同一段区间,先合并某一对,还是后合并某一对,完全对答案的优劣没有任何的影响
这是完全不同的
也就是说,我们在这个题目中,设计的状态没有必要去考虑这个区间被组合是顺序,因为这个完全不会导致答案的不同
那我们就直接按照二进制进行组合不就好了?
这样就能够遍历过所有的可能的答案了
这其实就是倍增优化的适用区间
当我们在意的答案只收到区间大小的影响的时候或者在确定了起始位置和区间大小后,我们的答案就可以被确定时,倍增优化就是一个可行的选择
我们可以通过对每一个点,进行logn次计算,来得到这个点到后面2^i(0<=i<n)的位置的答案,再在第二遍中,用这个消息,来组合得到所有可能的答案
最终实现了O(nlogn)的下限复杂度
我目前看到的倍增优化都是遵循这个规则的。
不知道之后会不会遇到更多的特殊的倍增优化有其他的规则或者说是模型
附上代码 (没有数据测。。但是还是写了)
#include<bits/stdc++.h> #define ll long long using namespace std; inline int read() { char c=getchar();int a=0,b=1; for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1; for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b; } string s1,s2,s3; int n1,n2; ll f[105][32]; int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); getline(cin,s3); int flag=0; for(int i=0;i<s3.size();i++) { if(s3[i]=='"'&&flag==0) { flag=1; } if(flag==1&&s3[i]!='"') { s2+=s3[i]; } if(flag==1&&s3[i]=='"') { flag=2; } if(flag==2&&s3[i]=='=')n2=s3[i+1]-'0'; if(s3[i]=='"'&&flag==2) { flag=3; } if(flag==3&&s3[i]!='"') { s1+=s3[i]; } if(flag==3&&s3[i]=='"') { flag=4; } if(flag==4&&s3[i]=='=')n1=s3[i+1]-'0'; } cout<<s1<<' '<<n1<<' '<<s2<<' '<<n2<<endl; for(int i=0;i<s1.size();i++) { int pos=i; f[i][0]=0; for(int j=0;j<s2.size();j++) { int cnt=0; while(s1[pos]!=s2[j]) { pos=(pos+1)%s1.size(); if(++cnt>s1.size()) { cout<<"0"<<endl; return 0; } } pos=(pos+1)%s1.size(); f[i][0]+=cnt+1; } } for(int j=1;j<=30;j++) { for(int i=0;i<s1.size();i++) { f[i][j]=f[i][j-1]+f[(i+f[i][j-1])%s1.size()][j-1]; } } ll m=0; for(int st=0;st<s1.size();st++) { ll x=st,ans=0; for(int k=30;k>=0;k--) { if(x+f[x%s1.size()][k]<=n1*s1.size()) { x+=f[x%s1.size()][k]; ans+=(1<<k); } } m=max(m,ans); } cout<<m/n2<<endl; return 0; }