Codeforces778E-Selling Numbers
题解:
Because the target value for this problem is calculated independently for all digits, we’ll use the dynamic programming approach. Define as the maximum possible cost of digits after we processed least significant digits in and is the set of numbers having the carry in current digit. This information is sufficient to choose the digit in the current position in and recalculate the set and value for the next digit.
The key observation is that there are only possible sets instead of . Consider last digits of and . Sort all the length- suffixes of in descending lexicographical order. Because all these suffixes will be increased by the same value, the property of having the carry is monotone. That means that all possible sets are the prefixes of length of this sorted list of suffixes. This fact allows us to reduce the number of states to . Sorting all suffixes of can be accomplished using the radix sort, appending the digits to the left and recalculating the order.
The only thing that’s left is to make all transitions in time. To do that, maintain the total cost of all digits and the amount of numbers that have the carry. After adding one more number with carry in current digit, these two values can be easily recalculated. After processing all digits in , we have to handle the remaining digits in (if there are any) and take the best answer. Total running time is .
CF的题解确实非常优秀。
Code:
#include<bits/stdc++.h>
#define N 1005
using namespace std;
int dp[N][N],n,m,k;
int f[N],g[N],a[N],len[N],b[N][N],cnt[10],val[10];
char s[N];
int main()
{
scanf("%s",s);
n=k=strlen(s);
for(int i=1;i<=n;i++)a[i]=s[n-i]-'0';
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s);
len[i]=strlen(s);
k=max(k,len[i]);
for(int j=1;j<=len[i];j++)
b[i][j]=s[len[i]-j]-'0';
f[i]=i;
}
for(int i=0;i<10;i++)scanf("%d",&val[i]);
//将dp[k][C]定义为在处理了A中的k个最小有效数字后的数字的最大可能成本,C是当前数字中包含进位的数字的集合。
memset(dp,0xef,sizeof(dp));
dp[0][m]=0;
k++;
for(int x=1;x<=k;x++)
{
int l=0,r=9;
if(a[x]<=9)l=r=a[x];else if(x==n)l=1;
for(int i=l;i<=r;i++)
{
int sum=0,s=0;
for(int j=1;j<=m;j++)
{
int o=i+b[j][x];
if(!o)
{
if(x<=len[j]||x<=n)
sum+=val[0];
}else
if(o>=10)
{
sum+=val[o-10];
s++;
}else sum+=val[o];
}
for(int j=m;j>=0;j--)
{
if(j<m)
{
int tmp=f[j+1],o=i+b[tmp][x];
if(o!=9)
{
if(!o&&x>n&&x>len[tmp])sum+=val[1];else
sum+=val[o%10+1]-val[o%10];
}else sum+=val[0]-val[9],s++;
}
dp[x][m-s]=max(dp[x][m-s],dp[x-1][j]+sum);
}
}
for(int i=0;i<10;i++)cnt[i]=0;
for(int i=1;i<=m;i++)cnt[b[i][x]]++;
for(int i=1;i<10;i++)cnt[i]+=cnt[i-1];
for(int i=m;i>=1;i--)g[cnt[b[f[i]][x]]--]=f[i];
memcpy(f,g,sizeof(g));
}
printf("%d\n",dp[k][m]);
return 0;
}
上一篇: Spring - IoC
下一篇: 用户IP访问次数统计