关于状态机dp的诡异做法
  • 板块P1874 快速求和
  • 楼主lyx128
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/12/14 22:36
  • 上次更新2024/12/15 09:55:58
查看原帖
关于状态机dp的诡异做法
1013479
lyx128楼主2024/12/14 22:36
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=80;
const int M=2e5;
char s[N+5],len;
ll n;
ll dp[N+5][2][M+5];//dp[i][1][k]表示在i之前插入+,凑成k的最小次数 

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>s+1>>n;
	len=strlen(s+1);
	memset(dp,0x3f,sizeof(dp));
	ll num=0;
	for(ll i=1;i<=len;i++){
		num=num*10+s[i]-'0';
		if(num>n)
			break;
		dp[i][0][num]=0;
	}
	for(ll i=2;i<=len;i++){
		//cout<<"when "<<i<<":\n";
		//不加+
		//cout<<"    situation1(not put +):\n";
		ll num=s[i]-'0';
		for(ll j=i-1,x=10;j>=1;j--,x*=10){
			if(num>n)break;
			num=num+(s[j]-'0')*x;
			for(ll k=num;k<=n;k++){
				dp[i][0][k]=min({dp[i][0][k],dp[j-1][1][k-num]+1,dp[j-1][0][k-num]+1});
				//cout<<"    try "<<k<<",pre[1,"<<j-1<<"]+"<<num<<" is ok,min opt is "<<dp[i][0][k]<<"\n"; 
			}
		}
		//加+ 
		//cout<<"    situation2(put +):\n";
		for(ll j=s[i]-'0';j<=n;j++){
			dp[i][1][j]=min({dp[i][1][j],dp[i-1][0][j-(s[i]-'0')]+1,dp[i-1][1][j-(s[i]-'0')]+1});
			//cout<<"        try "<<j<<",min opt is "<<dp[i][1][j]<<"\n";
		}
	}
	cout<<((min(dp[len][1][n],dp[len][0][n])==0x3f3f3f3f3f3f3f3f)?(-1):(min(dp[len][1][n],dp[len][0][n])))<<"\n";
	return 0;
}

欢迎各位大佬hack!!!

2024/12/14 22:36
加载中...