[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| \neq |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} \rfloor \)。于是可以发现,在这种情况下,当\(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} \rfloor \)也可以得到最优解。

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


 

   此时,若\(x\)的最后一位不为\(9\)或者\(x\)的倒数第二位为偶数,则可以令\(a=\lfloor \frac{x}{2}\rfloor, 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 (\bmod 11)\),故只能让\(|c|=|x|-2\),令\(a=\lfloor \frac{x}{2}\rfloor, b=a+1\)即可

   最后只剩下\(x\)为奇数,\(x \equiv 10 (\bmod 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}\rfloor, 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 (\bmod 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\n%s\n%s\n",t,t,t);
        return;
    }
    if(n==1){
        printf("%d\n%d\n-\n",(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\n%s\n%s\n",t,x,t,t);
        return;
    }
    if(s[n-1]!='9'){
        Div(n,2);
        int m=strlen(t);
        printf("%s\n",t);
        t[m-1]++;
        printf("%s\n",t);
        t[m-1]='\0';
        printf("%s\n",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("\n%s",t);
        for(int i=0;i<=m;i++)printf("%d",i&1?9:0);
        printf("\n%s",t);
        for(int i=0;i<m;i++)printf("%d",i&1?9:0);
        printf("\n");
        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("\n");
    if(t[0]!='0')printf("%s",t);
    for(int i=0;i<=m;i++)printf("%d",i&1?0:9);
    printf("\n");
    if(t[0]!='0')printf("%s",t);
    for(int i=0;i<m;i++)printf("%d",i&1?0:9);
    printf("\n");
}
int main()
{
    scanf("%d",&T);
    while(T--)init();
}
View Code

 

posted @ 2020-11-25 15:59  DeaphetS  阅读(307)  评论(0编辑  收藏  举报