【51NOD 1666】最大值

本文介绍了一种结合数位动态规划(DP)与贪心策略解决特定数学运算问题的方法,通过实例演示如何找到使特定运算结果最大的数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

定义一种新的运算符$。
具体地,A$B(p)的值可以用如下代码来表示。

while (A) {a[cnta++]=A%10; A/=10;}
while (B) {b[cntb++]=B%10; B/=10;}
for  (int  i=0; i<cnta/2; i++) swap(a[cnta-i-1],a[i]);
for  (int  i=0; i<cntb/2; i++) swap(b[cntb-i-1],b[i]);
nowa=nowb=0;
for (int i=1; i<=p; i++)
{
    ans+=a[nowa]*b[nowb];
    nowa=(nowa+1)%cnta; nowb=(nowb+1)%cntb;
}
return ans;

其中ans的值就是这个表达式的值。

已知k,p,它想找出一个x,使得l<=x<=rx$k(p)最大。

例如l=2,r=11,k=4,p=2,那么当x=9时能使x$k(p)达到最大值。

1<=l<=r<10100000,1<=k<10100000,100000<=p<=1016

Solution

这个很显然就是数位DP嘛,
把每一位的系数求出来,(这个大家自己手推一下都能搞出来,细节比较多)
再贪心一下,我的做法是先把最高位的相同的位数剃掉(ans一定),剩下的就显然的贪心了,
贪心时可以先把高位中相同的位数先计算,剩下的就简单了。

复杂度:O(n)

Code

#include <cstdio>
#include <cstdlib>
#define max(q,w) ((q)<(w)?(w):(q))
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const LL N=1e6+5;
LL n,m,m1;
LL P,ans;
int b[N],zx[N];
int L[N],R[N];
LL f[N],g[N*2];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
void swap(LL &q,LL &w){LL t=w;w=q;q=t;}
void swap(int &q,int &w){int t=w;w=q;q=t;}
int main()
{
    freopen("!.in","r",stdin);
    LL q,w;char ch=' ';
    for(;(ch<'0')||(ch>'9');ch=getchar());
    for(;ch>='0' && ch<='9';ch=getchar())L[++L[0]]=ch-48;
    for(;(ch<'0')||(ch>'9');ch=getchar());
    for(;ch>='0' && ch<='9';ch=getchar())R[++R[0]]=ch-48;
    for(;(ch<'0')||(ch>'9');ch=getchar());
    for(;ch>='0' && ch<='9';ch=getchar())b[++b[0]]=ch-48;
    fo(i,1,L[0]/2)swap(L[i],L[L[0]-i+1]);
    fo(i,1,R[0]/2)swap(R[i],R[R[0]-i+1]);
    scanf("%lld",&P);
    if(L[0]<R[0])
    {
        q=P/b[0];w=P%b[0];
        LL t=9;
        fo(i,1,b[0])ans+=(q+((LL)i<=w))*b[i]*t;
        printf("%lld\n",ans);return 0;
    }
    n=L[0];m=b[0];
    m1=gcd(m,n);w=P/(n/m1*m);
    fo(I,1,m1)
    {
        g[I%m1]=0;
        for(int i=I;i<=m;i+=m1)g[I%m1]+=b[i];
    }
    fo(i,1,n)f[i]=g[i%m1]*w;
    w=P%(n/m1*m);
    fo(I,1,m1)
    {
        g[0]=0;g[1]=b[I];q=zx[I]=1;
        for(int i=(I-1+n)%m;i!=I-1;i=(i+n)%m)g[++q]=b[i+1],zx[i+1]=q;
        fo(i,q+1,2*q)g[i]=g[i-q];
        fo(i,2,2*q)g[i]+=g[i-1];
        q=w/n+2;
        for(LL i=I;i<=n;i+=m1)
        {
            while(q*n-n+i>w&&q!=0)q--;
            f[i]+=g[zx[(i-1)%m+1]-1+q]-g[zx[(i-1)%m+1]-1];
        }
    }
    fo(i,1,n/2)swap(f[i],f[n-i+1]);
    LL ans1=0;
    ans=0;
    while(L[n]==R[n]&&n)ans+=L[n]*f[n],n--;
    ans1=ans;
    fo(i,1,n)
    {
        ans+=R[i]*f[i];
        if(R[i])ans=max(ans,(R[i]-1)*f[i]+ans1);
        ans1+=9*f[i];
    }
    printf("%lld\n",ans);
}
### 关于51Nod平台上编号为1020的问题详情与解答 #### 问题描述 在51Nod平台上的第1020号问题是关于计算两个大整数相加的结果[^1]。给定两个正整数A和B,长度不超过10^6位,要求编写程序来求解这两个数的和。 #### 输入格式说明 输入数据由多组测试案例组成;每组测试案例占两行,分别表示要相加的大整数A和B。对于每一组测试案例,应当单独输出一行结果,即A+B的值。 #### 解决方案概述 解决此问题的关键在于处理超大数据类型的运算,在大多数编程语言中内置的数据类型无法直接支持如此大规模数值的操作。因此,可以采用字符串的方式来存储这些大整数,并实现逐位相加逻辑,同时考虑进位情况。 下面是一个Python版本的具体实现方法: ```python def add_large_numbers(a: str, b: str) -> str: # Reverse strings to make addition easier from least significant digit a = a[::-1] b = b[::-1] carry = 0 result = [] max_length = max(len(a), len(b)) for i in range(max_length): digit_a = int(a[i]) if i < len(a) else 0 digit_b = int(b[i]) if i < len(b) else 0 total = digit_a + digit_b + carry carry = total // 10 current_digit = total % 10 result.append(str(current_digit)) if carry != 0: result.append(str(carry)) return ''.join(reversed(result)) if __name__ == "__main__": while True: try: num1 = input().strip() num2 = input().strip() print(add_large_numbers(num1, num2)) except EOFError: break ``` 该代码片段定义了一个函数`add_large_numbers`用于接收两个作为参数传入的大整数(形式上为字符串),并返回它们之和同样作为一个字符串。通过反转输入字符串使得最低有效位位于索引位置0处从而简化了按位累加的过程。最后再将得到的结果列表反向拼接成最终答案输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值