社区讨论

90pts WA#7 内有思路 求调

P1874快速求和参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mhj2wi9d
此快照首次捕获于
2025/11/03 19:50
4 个月前
此快照最后确认于
2025/11/03 19:50
4 个月前
查看原帖

思路

数组定义

dpi,kdp_{i,k} 表示使用 ii 个加号以及前 jj (即字符串s的前 jj )个数字所能组成的与 nn 差值最小的数
显而易见 0i<lens0≤i<len_s ; ij<lensi≤j<len_s ;

转移方程

0__________ i___________k__________j
_____________________
对于 dpi.jdp_i._j 我们可以发现他的取值来源于本身或通过少使用一个加号的前状态转移,我们可以枚举最后一个加号(第 ii 个加号)的位置 kk1j1-j 分为 1k1-kk+1jk+1-j 两段,其中前一段用了 i1i-1 个加号而后一段没有使用 故得到转移方程:
if(ndpi,j>ndpi1,knum(k+1)j)dpi,j=dpi1,k+num(k+1)jif(|n-dp_{i,j}|>|n-dp_{i-1,k}-num_{(k+1)⇨j}|) dp_{i,j}=dp_{i-1,k}+num_{(k+1)⇨j}

代码

CPP
#include<bits/stdc++.h>
using namespace std;
const int MAXN=42;
string s;
int n;
long long dp[MAXN][MAXN];
int main(){
	memset(dp,0x3f,sizeof(dp));
	cin>>s;
	scanf("%d",&n);
	int N=s.size();
	dp[0][0]=0;
	for(int i=1;i<=N;i++){
		dp[0][i]=min(dp[0][i-1]*10+(s[i-1]-'0'),dp[0][i]);
	}
	for(int i=1;i<N;i++)
	    for(int j=i;j<=N;j++)
	        for(int k=j-1;k>=i;k--){
	        	int cnt=0;
	        	for(int x=k+1;x<=j;x++){
	        		cnt=cnt*10+(s[x-1]-'0');
	        		if(cnt>1e5+2) break;
				}
	        	if(abs(n-dp[i][j])>abs(n-dp[i-1][k]-cnt)) dp[i][j]=dp[i-1][k]+cnt;
			}
	for(int i=0;i<N;i++)
		if(dp[i][N]==n){
			printf("%d",i);
			return 0;
		}
	printf("-1");
	return 0;
}

回复

0 条回复,欢迎继续交流。

正在加载回复...