妹子刚学简单dp对拍无果求调
查看原帖
妹子刚学简单dp对拍无果求调
556545
_anll_楼主2024/10/31 14:43

rt,大概思路是令 dp[i][j]dp[i][j] 表示第 ii 个问号选择 jj 时的最大答案,转移时枚举前一个问号点的选择,加上两点之间的固定答案,再减去因为第 ii 个问号的选择而变成减的值,但因为可能这个值在前面就被减去过,所以需要加回来这样。红红绿绿的真的不知道哪错了,跪求大佬捞捞 QAQ!

#include<iostream>
#define int long long
using namespace std;
const int N=3e5+5;
int t,n,tot,num[N],id[N],dp[N][30],w[N][30];
int val[27]={0,1,5,10,50,100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000,50000000,100000000,500000000,1000000000,5000000000,10000000000,50000000000,100000000000,500000000000,1000000000000,5000000000000};
string s;
void solve(){
	for(int i=1;i<=n;i++) num[i]=0;
	cin>>s;n=s.size();s='6'+s;
	int maxn=0;tot=0;
	for(int i=n;i>=1;i--){
		if(s[i]=='?') continue;
		if(maxn>s[i]-'A'+1) num[i]=-val[s[i]-'A'+1];
		else{
			maxn=s[i]-'A'+1;
			num[i]=val[s[i]-'A'+1];
		}
	} 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=26;j++){
			w[i][j]=w[i-1][j];
			if(s[i]-'A'+1<=j) w[i][j]+=max(0ll,num[i]);
		}
	}
	for(int i=1;i<=n;i++) for(int j=1;j<=26;j++) dp[i][j]=-0x3f3f3f3f3f3f3f3f;
	int ss=0;
	for(int i=1;i<=n;i++){
		ss+=num[i];
		if(s[i]!='?') continue;int pre=id[tot];id[++tot]=i;
		for(int j=1;j<=26;j++){
			for(int k=j;k<=26;k++){
				dp[tot][j]=max(dp[tot][j],dp[tot-1][k]+ss-2*w[i][j-1]+2*w[pre][j-1]);
			}
			dp[tot][j]+=val[j];
		}
		ss=0;
	}
	int ans=0;
	for(int i=1;i<=26;i++) ans=max(ans,dp[tot][i]);
	cout<<ans+ss<<endl;
	string an;int pre=n+1;
	for(int i=n;i;i--){
		if(s[i]!='?') continue;
		else{
			if(pre==n+1){
				for(int j=1;j<=26;j++) 
					if(dp[tot][j]==ans) s[i]=(char)(j+'A'-1);
			}
			else{
				int maxn=0,pl=0,j=s[id[tot+1]]-'A'+1;
				for(int k=1;k<=j;k++){
					if(dp[tot][k]-2*w[id[tot+1]][-1]+2*w[i][j-1]>maxn)
					maxn=dp[tot][k]-2*w[id[tot+1]][j-1]+2*w[i][j-1],pl=k;
				}
				s[i]=(char)(pl+'A'-1);
			}
			pre=i;tot--;
		}
	}
	for(int i=1;i<=n;i++) cout<<s[i];
	cout<<endl;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>t;while(t--) solve();
	return 0;
}
2024/10/31 14:43
加载中...