Codeforces Round #451 (Div. 2) F. Restoring the Expression(哈希)

本文介绍了一种解决特定问题的算法:给定一个仅包含数字的字符串,通过插入加号和等号使其形成正确的数学表达式。文章详细阐述了解决方案的思路,并提供了具体的实现代码。

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

F. Restoring the Expression

Problem Statement

    A correct expression of the form a+b=c was written; a, b and c are non-negative integers without leading zeros. In this expression, the plus and equally signs were lost. The task is to restore the expression. In other words, one character ‘+’ and one character ‘=’ should be inserted into given sequence of digits so that:

    character’+’ is placed on the left of character ‘=’,
    characters ‘+’ and ‘=’ split the sequence into three non-empty subsequences consisting of digits (let’s call the left part a, the middle part — b and the right part — c),
    all the three parts a, b and c do not contain leading zeros,
    it is true that a+b=c.

    It is guaranteed that in given tests answer always exists.

Input

    The first line contains a non-empty string consisting of digits. The length of the string does not exceed 106.

Output

    Output the restored expression. If there are several solutions, you can print any of them.
    Note that the answer at first should contain two terms (divided with symbol ‘+’), and then the result of their addition, before which symbol’=’ should be.
    Do not separate numbers and operation signs with spaces. Strictly follow the output format given in the examples.
    If you remove symbol ‘+’ and symbol ‘=’ from answer string you should get a string, same as string from the input data.

Examples

Example 1
    Input
        12345168
    Output
        123+45=168
Example 2
    Input
        099
    Output
        0+9=9
Example 3
    Input
        123123123456456456579579579
    Output
        123123123+456456456=579579579

题意

    给定一个全由数字组成的字符串,让你在中间添加一个加号和一个等号,使它所表示出来的等式成立。且前两个数必为加数,即输出格式为a+b=c。

思路

    其实,这题不难。对于一个两个数加法的式子,我们知道,结果最多也只会比最大的那个数多1位,要不结果就和两个加数中大的那个数的位数相等,只有两种情况,于是我们可以这样考虑,对于给出的字符串,我们先进行哈希(我模数取了1e9+7,可以过),然后从右往左枚举结果有几位,那么左边的加数有两种情况,一种是第一个加数与结果位数相等或少1,另一种是第二个加数与结果位数相等或少1,那对于每一位,我们最多只有4种情况,且有很多情况都是无用的。
    那么对于一个数如何哈希回来,我们可以对那个字符串进行后缀和,然后对于一个区间[l,r]为一个选定的数,我们就可以通过sum[l]-sum[r+1]来获得这个数哈希以后乘上10lenr的值,然后我们要除掉10lenr,这个可以通过预处理逆元来完成,最后判一下可不可行,可行直接输出就好了。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const ll mod=1e9+7;
int n;
char s[1000010];
ll num[1000010],inv[1000010];
inline ll pw(ll a,ll b) {
    ll res=1;
    while(b) {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
inline void printstr(int l,int r) {
    for(int i=l;i<=r;i++)
        putchar(s[i]);
}
inline ll calc(int l,int r) {
    ll val=((num[l]-num[r+1])%mod+mod)%mod;
//  cout<<"interval :"<<l<<"->"<<r<<" get:"<<val<<endl;
    return (val*inv[n-r]%mod);
}
inline bool check(ll l1,ll l2,ll l3) {
//  cout<<"Now check three lengths:"<<l1<<" and "<<l2<<" and "<<l3<<endl;
    if(l1>l3||l2>l3||l1<1||l2<1||l3<1)
        return 0;
    int pl1=1,pl2=l1+1,pl3=l1+l2+1,pr1=l1,pr2=l1+l2,pr3=l1+l2+l3;
//  cout<<"Num one:"<<pl1<<" to "<<pr1<<" Num two:"<<pl2<<" to "<<pr2<<" Num three:"<<pl3<<" to "<<pr3<<endl;
    if(s[pl1]=='0'&&pr1-pl1+1!=1)
        return 0;
    if(s[pl2]=='0'&&pr2-pl2+1!=1)
        return 0;
    if(s[pl3]=='0'&&pr3-pl3+1!=1)
        return 0;
//  cout<<"First num:"<<calc(pl1,pr1)<<" Second num:"<<calc(pl2,pr2)<<" Third num:"<<calc(pl3,pr3)<<endl;
    if((calc(pl1,pr1)+calc(pl2,pr2))%mod==calc(pl3,pr3)) {
//      cout<<pl1<<" "<<pr1<<" "<<pl2<<" "<<pr2<<" "<<pl3<<" "<<pr3<<endl;
        printstr(pl1,pr1);
        putchar('+');
        printstr(pl2,pr2);
        putchar('=');
        printstr(pl3,pr3);
        return 1;
    }
    return 0;
}
int main() {
//  freopen("F.in","r",stdin);
    inv[1000000]=pw(10LL,1000000LL);
    inv[1000000]=pw(inv[1000000],mod-2);
    for(int i=999999;~i;i--)
        inv[i]=inv[i+1]*10%mod;
    scanf("%s",s+1);
//  for(int i=0;i<=10;i++)
//      cout<<inv[i]<<endl;
    n=strlen(s+1);
//  cout<<n<<endl;
//  for(int i=1;i<=n;i++)
//      putchar(s[i]);
    num[n+1]=0;
    for(int i=n;i;i--)
        num[i]=(num[i+1]+(s[i]-'0')*pw(10LL,n-i)%mod)%mod;
//  for(int i=n;i;i--)
//      cout<<num[i]<<" ";
//  cout<<endl;
    for(int div=1;div<=n;div++)
        if(check(div-1,n-div-(div-1),div)||check(div,n-div-div,div)||check(n-div-(div-1),div-1,div)||check(n-div-div,div,div))
            return 0;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值