考虑每个数对于0的贡献,我们可以知道,一个2跟一个5可以贡献出一个10(即一个0),所以我们可以用前缀和记录2和5出现的数量。
对于2和5次数的统计,则去统计该数能被多少个2整除,多少个5整除,然后二分前缀和得到合法位置。
对于合法位置的获取,Lower bound去获得合法位置的开头,upper bound获得不合法位置的开头,所以upper bound-1是合法的位置的结尾
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long ll;
typedef pair<ll,ll> pll;
int mod=1e9+7;
int cnt2[N],cnt5[N];
void solve()
{
int n,k;
cin>>n>>k;
vector<ll> a(n+1);
for(int i=0;i<=n;i++) cnt2[i]=cnt5[i]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
ll x=a[i];
while(x%2==0){
x/=2;
cnt2[i]++;
}
cnt2[i]+=cnt2[i-1];
while(x%5==0){
x/=5;
cnt5[i]++;
}
cnt5[i]+=cnt5[i-1];
}
ll ans=0;
for(int i=1;i<=n;i++){
int p2=k+cnt2[i-1],p5=cnt5[i-1]+k;
int l2=lower_bound(cnt2,cnt2+n+1,p2)-cnt2,r2=upper_bound(cnt2,cnt2+n+1,p2)-cnt2-1;
int l5=lower_bound(cnt5,cnt5+n+1,p5)-cnt5,r5=upper_bound(cnt5,cnt5+n+1,p5)-cnt5-1;
int l=max(l2,l5),r=max(r2,r5);
l=max(l,i);
if(l==n+1) continue;
ans+=(r-l+1);
}
cout<<ans<<endl;
}
int main ()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
思路:DP,表示前i个字符串中有j个相同且hash值为k的情况。
注意,此处的dp和以往不同,例如01背包,我们的状态转移方程为 类似于这种,即当前的状态由之前的状态所得到,但对于该题我们发现,当前状态不好用之前的状态进行表示,因为对于hash值k,我们不好根据当前的值去算出之前的值,所以我们可以用当前的状态去表示之后状态。即:
因为题目要求输出路径所以需要另开一个数组进行记录,最后根据答案进行回溯即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5;
int dp[60][60][1005];
char f[60][60][1005];
ll pp[N];
void solve()
{
memset(dp,0,sizeof dp);
ll n,b,p,k;
cin>>n>>b>>p>>k;
string s;
cin>>s;
s=" "+s;
pp[n]=1;
for(int i=n-1;i>=1;i--){
pp[i]=pp[i+1]*b%p;
}
ll val=0;
for(int i=1;i<=n;i++){
val=(val+s[i]*pp[i])%p;
}
dp[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
for(int t=0;t<p;t++){
if(dp[i][j][t]==0) continue;
for(ll ch='a';ch<='z';ch++){
if(ch==s[i+1]){
dp[i+1][j+1][(t+(ch)*pp[i+1])%p]=1;//状态转移
f[i+1][j+1][(t+(ch)*pp[i+1])%p]=ch;
}
else{
dp[i+1][j][(t+(ch)*pp[i+1])%p]=1;//状态转移
f[i+1][j][(t+(ch)*pp[i+1])%p]=ch;
}
}
}
}
}
if(!dp[n][k][val]) cout<<-1<<endl;
else{
string ans;
ll vv=val;
int kk=k;
for(int i=n;i>=1;i--){//回溯过程
ll ch=f[i][kk][vv];
ans+=(char)ch;
if(ch==s[i]) kk--;
vv=(vv+p-pp[i]*(ch)%p)%p;
}
reverse(ans.begin(),ans.end());
cout<<ans<<endl;
}
}
int main()
{
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}