AT214 連射王高橋君 题解
前言
CSP2021 前的题解。
思路
看到输出序列,不难想到动态规划实现。即
而我们可以发现动态规划会有两个缺陷:
- 空间太大,足足
10^{18} ,因此不可行。 - 难以实现,直接DP不能存储方案
对于第二点,我们可以使用记忆化搜索等效替代,但空间的优化需要我们进行思考。如果是学习了数位DP的同学,肯定发现这道题和数位DP都有一个共同点:需要的数字都太大,我们无法直接存储或进行DP。如果是数位DP,我们会存储下当前位数和上一位的数字。那么我们同样可以将这个思路代入这道题。
于是有对于
不难发现,我们最多使用
但是,每个数并不只有一位非零,不能一用就抛弃,那么我们新增状态
那么空间与时间上就完全可行了,相信输出序列对大家并不难。
code
#include<bits/stdc++.h>
using namespace std;
int dp[20][100][12][12];//在看第i位的时候,你还需要凑j,之前已有t个数字,当前位最多有k个没有花费时的最大长度。
int tway[12][20],way[12][20];
int num[20],n,len,ans=INT_MAX;
bool vis[10];
void dfs(int dep,int sum,int free,int u,int res) {
if(dep==n+1) {
if(sum!=0) return;
if(ans>res-(free==1)) {
len=free;
ans=res-(free==1);
for(int i=1;i<=len;++i) {
for(int j=1;j<=n;++j) {
way[i][j]=tway[i][j];
}
}
}
return;
}
if(free>=10) return;
if(dp[dep][sum][free][u]<=res) return;
dp[dep][sum][free][u]=res;
for(int i=0;i<=9;++i) {
if(i>sum) break;
if(vis[i]) {
int las=sum-i;
if(las<10) {
if(u==0) {
tway[free+1][dep]=i;
dfs(dep+1,las*10+num[dep+1],free+1,free+1,res+n-dep+2);
tway[free+1][dep]=0;
}
else {
tway[u][dep]=i;
dfs(dep+1,las*10+num[dep+1],free,free,res);
tway[u][dep]=0;
}
}
if(u==0) {
tway[free+1][dep]=i;
dfs(dep,las,free+1,0,res+n-dep+2);
tway[free+1][dep]=0;
}
else {
tway[u][dep]=i;
dfs(dep,las,free,u-1,res);
tway[u][dep]=0;
}
}
}
}
char str[20];
long long tar;
int main() {
memset(dp,127,sizeof(dp));
cin>>str+1;
for(int i=strlen(str+1);i>=1;--i) vis[str[i]-'0']=1;
scanf("%lld",&tar);
while(tar) {
num[++n]=tar%10;
tar/=10;
}
for(int i=1;i<=n/2;++i) swap(num[i],num[n-i+1]);
dfs(1,num[1],0,0,0);
for(int i=1;i<len;++i) {
bool fl=0;
for(int j=1;j<=n;++j) {
if(!fl&&!way[i][j]) continue;
fl=1;
printf("%d",way[i][j]);
}
printf("+");
}
bool fl=0;
for(int j=1;j<=n;++j) {
if(!fl&&!way[len][j]) continue;
fl=1;
printf("%d",way[len][j]);
}
if(len!=1) printf("=\n");
return 0;
}