P1874 快速求和 题解
upd on 2023/12/22:修改了代码,现已通过所有 hack 数据。
首先定义状态:
-
令
dp_{i,j} 表示前i 个数字要变成j 所需要的最少加号个数。 -
同时,我们还需要一个辅助数组:令
num_{i,j} 表示i \sim j 的数字组成的数(不添加加号)。
然后进行转移。
显然可以枚举每个添加加号的位置
朴素转移即可。
注意特判
时间复杂度
需要注意字符串中的
代码:
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
string str;
int s,n,tot;
int a[100031];
int num[55][55];
int dp[55][100031];
bool z;
signed main(){
srand(time(0));
cin>>str>>s;
n=str.size();
for(int i=0;str[i];i++){
if(str[i]!='0') z=1;
if(z) a[++tot]=str[i]-'0';
}
for(int i=1;i<=tot;i++){
num[i][i]=a[i];
for(int j=i;j-i<=11&&j<=tot;j++)
num[i][j]=num[i][j-1]*10+a[j];
}
for(int i=0;i<=tot+1;i++)
for(int j=0;j<=s+1;j++)
dp[i][j]=0x7fffffff;
dp[0][0]=0;
for(int i=1;i<=tot;i++)
for(int k=1;k<=11;k++)
if(i>=k)
for(int j=num[i-k+1][i];j<=s;j++)
dp[i][j]=min(dp[i][j],dp[i-k][j-num[i-k+1][i]]+1);
if(dp[tot][s]>tot) cout<<-1;
else cout<<dp[tot][s]-1;
return 0;
}