欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Codeforces778E-Selling Numbers

程序员文章站 2022-07-12 13:59:10
...

Codeforces778E-Selling Numbers
题解:
Because the target value for this problem is calculated independently for all digits, we’ll use the dynamic programming approach. Define dpk,C as the maximum possible cost of digits after we processed k least significant digits in A and C is the set of numbers having the carry in current digit. This information is sufficient to choose the digit in the current position in A and recalculate the C set and DP value for the next digit.
The key observation is that there are only n+1 possible sets instead of 2n. Consider last k digits of A and Bi. Sort all the length-k suffixes of Bi 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 C are the prefixes of length m(0mn) of this sorted list of suffixes. This fact allows us to reduce the number of DP states to O(n·|A|). Sorting all suffixes of Bi 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 DP transitions in O(1) 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 A, we have to handle the remaining digits in Bi (if there are any) and take the best answer. Total running time isCodeforces778E-Selling Numbers .
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;
}