[2020 小米邀请赛][E. Rikka with Subsequence]

因为这题错失了1k RMB+小米手表,心塞塞...

题目链接:https://ac.nowcoder.com/acm/contest/9328/E

题目大意:给定一个数字(x),(x)的长度不超过(5000)位,设有两个数(a,b)满足(a+b=x),(a)与(b)的字符串形式的最长公共子序列为(c),要求输出一个使(c)的长度尽可能长的方案

题解:记(|x|)表示数字(x)的长度,考虑(|c|)的理论最大值

   显然,当且仅当(x[0]>1)且(x)为偶数时,可以取到(|c|=|x|)

   若(x)为偶数,且(|c| eq |x|),那么此时一定有(x[0]=1),可以得出最优解是(a=b=frac{x}{2}),此时(|c|=|x|-1)

   若(x)为奇数,那么一定有(|c|le |x|-1),假设有(b=10a+k(k<10))使得(a+b=x),那么可以发现当(x)对(11)取模的值不为(10)时,有(|c|=|a|)的解,其中,(a=lfloor frac{x}{11} floor )。于是可以发现,在这种情况下,当(x)的前两位的值大于等于(11)时,可以取到(|c|=|x|-1),否则会有以下两种情况:

    (x)为个位数,此时可以特判

    (x)是(10)开头的,可以发现,这个时候(|a|)与(|b|)的取值只可能是:(|a|=|x|, |b|le |x|-2)或(|a|=|x|-1, |b|le |x|-1)(这里不妨设(|a|ge|b|))。在第一种情况下,有(|c|le |x|-2),在第二种情况下,由于(x)为奇数,如果(|c|=|x|-1=|a|)则会推出(a=b),从而导致矛盾。因此,此时的最优解只可能是(|c|=|x|-2),同样取(a=lfloor frac{x}{11} floor )也可以得到最优解。

   剩下(x)为奇数,且(x equiv 10 (mod 11))的情况。一开始我的思路如下(可略过):


   此时,若(x)的最后一位不为(9)或者(x)的倒数第二位为偶数,则可以令(a=lfloor frac{x}{2} floor, b=a+1),此时有(|c|=|a|-1)。当(x[0]>1)时,(|c|=|x|-1),否则当(x[0]=1)时,考虑是否还有让(|c|=|x|-1)的可能

   在这种情况下,考虑(|a|)与(|b|)的取值,可以发现,有(|a|=|x|, |b|le |x|-1)或(|a|=|x|-1, |b|le |x|-1)。显然由于(x)为奇数,第二种情况下不能取到最优解。而在第一种情况下,由于要取到(|c|=|x|-1),因此(a)只可能是(b)中间再塞进去一位。而又因为(x)是奇数,所以这一位只可能是最后一位(否则两个数个位相同相加为偶数),故只可能是(b=10a+k(k<10))的形式。但此时已有结论(x equiv 10 (mod 11)),故只能让(|c|=|x|-2),令(a=lfloor frac{x}{2} floor, b=a+1)即可

   最后只剩下(x)为奇数,(x equiv 10 (mod 11)),且(x)的末两位为(y9)((y)为奇数)的情况。如果(x)的倒数第三位为偶数,则可以将前面的部分和后面这两位分开,其中前面的部分除以二,后面的部分按照模(11)小于(10)来处理,这样可以证明是最优解(证明方法同上,此时(|c|=|x|-1)或(|x|-2))

   若(x)的倒数第三位为奇数,则可以让前面的部分除以二向下取整,末尾分别拼上二位数(p,q)使得(p+q=1y9),且(p)与(q)有一位相同。这时会发现除了(y=9)其余情况均能处理,于是考虑换一种思路


   如果(x)的最后一位不为(9),同样令(a=lfloor frac{x}{2} floor, b=a+1)。否则,则有(str(x)=str(y)+str(c)+str(99...9)),若(y)为偶数,则令(str(a)=str(frac{y}{2})+str(c)+str(0909..09),str(b)=str(frac{y}{2})+str(0)+str(9090..90))可得最优解(对于(x[0]=1)的情况讨论不再赘述,其实可以发现若(x[0]=1),(x)为奇数,且(x equiv 10 (mod 11)),(|c|le |x|-2)一定成立)。若(y)为奇数,则令(str(a)=str(frac{y-1}{2})+str(c+1)+str(9090..90),str(b)=str(frac{y-1}{2})+str(9)+str(0909..09))即可,需要注意的是如果(y=1)则不能将前导零输出

#include<bits/stdc++.h>
using namespace std;
#define N 5050
int T,n;
char s[N],t[N];
void Div(int n,int x)
{
    int m=strlen(t);
    memset(t,0,sizeof(char)*(m+5));
    int r=0,j=0;
    for(int i=0;i<n;i++){
        r=(r*10+s[i]-'0');
        if(r>=x || j>0){
            t[j++]=r/x+'0';
            r%=x;
        }
    }
    if(j==0)t[j++]='0';
}
void init()
{
    scanf("%s",s);
    n=strlen(s);
    if(s[n-1]%2==0){
        Div(n,2);
        printf("%s
%s
%s
",t,t,t);
        return;
    }
    if(n==1){
        printf("%d
%d
-
",(s[0]-'0')/2,(s[0]-'0')/2+1);
        return;
    }
    int x=0;
    for(int i=0;i<n;i++)x=(x*10+s[i]-'0')%11;
    if(x<10){
        Div(n,11);
        printf("%s%d
%s
%s
",t,x,t,t);
        return;
    }
    if(s[n-1]!='9'){
        Div(n,2);
        int m=strlen(t);
        printf("%s
",t);
        t[m-1]++;
        printf("%s
",t);
        t[m-1]='';
        printf("%s
",t);
        return;
    }
    int m=0;
    while(s[n-1]=='9')n--,m++;
    int k=s[n-1]-'0';
    n--;
    if(s[n-1]%2==0){
        Div(n,2);
        printf("%s%d",t,k);
        for(int i=0;i<m;i++)printf("%d",i&1?9:0);
        printf("
%s",t);
        for(int i=0;i<=m;i++)printf("%d",i&1?9:0);
        printf("
%s",t);
        for(int i=0;i<m;i++)printf("%d",i&1?9:0);
        printf("
");
        return;
    }
    Div(n,2);
    if(t[0]!='0')printf("%s",t);
    printf("%d",k+1);
    for(int i=0;i<m;i++)printf("%d",i&1?0:9);
    printf("
");
    if(t[0]!='0')printf("%s",t);
    for(int i=0;i<=m;i++)printf("%d",i&1?0:9);
    printf("
");
    if(t[0]!='0')printf("%s",t);
    for(int i=0;i<m;i++)printf("%d",i&1?0:9);
    printf("
");
}
int main()
{
    scanf("%d",&T);
    while(T--)init();
}
View Code
原文地址:https://www.cnblogs.com/DeaphetS/p/14036665.html