[NOIP2017模拟]回文数字

2017.11.9 T1 2048

题目描述
Tom 最近在研究回文数字。
假设 s[i] 是长度为 i 的回文数个数(不含前导0),则对于给定的正整数 n 有:
这里写图片描述

以上等式中最后面的括号是布尔表达式,Tom 想知道S[n] mod 233333 的值是多少。

输入格式
第一行一个正整数 T 。
接下来输出共 T 行,每行一个正整数 n 。

输出格式
输出共 T 行,每行一个整数,表示 S[n] mod 233333 。

样例数据
输入

1
2

输出

9

备注
【数据规模与约定】
对于 30% 的数据: n5
对于另 20% 的数据: n107
对于另 20% 的数据: T=1
对于 100% 的数据: T5105n109

分析:表示看到n竟然有 109 ,吓傻。然后去找规律,还真有(因为偶数项被bool判断掉了,我就只找了奇数项的规律,第一个数是n,第二个数是答案,第三个数是取模后):
[NOIP2017模拟]回文数字_第1张图片

然后就误入歧途,开始疯狂找取模后的规律(每次加的数都不一样怎么可能有规律……)。但找到的这种头几位是n-1中间夹(n-1)/2个7末尾9的规律对正解很有帮助, 109 只能log出答案,qianguch想到了倍增(真TM是个天才!)!用数组存 2130 个7的这种数的答案,就可以log求解了。
(其实我更纠结于取了模还可以正常运算吗,事实证明加、减、乘都是可以的)
然而真正的正解是用到了NOI知识的,因为233333不是质数,要求逆元,由于我写的是NOIP的总结,就不说了。

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

const int mo=233333;
int T,n,len;
long long shi[40],sum[40],x,y;

void pre()
{
    shi[0]=10;
    for(int i=1;i<=30;++i)
        shi[i]=(shi[i-1]*shi[i-1])%mo;//先得求有2^k个0的数
    sum[0]=7;
    for(int i=1;i<=30;++i)
        sum[i]=(sum[i-1]+sum[i-1]*shi[i-1])%mo;//现在可以求有2^k个7的数了
}

int main()
{
    freopen("bug.in","r",stdin);
    freopen("bug.out","w",stdout);

    pre();
    T=getint();
    while(T--)
    {
        n=getint();
        if(n%2==0)//偶数判掉
            n=n-1;
        len=n/2;
        x=9,y=10;//先把个位的9加上,y记录7应该从第几位开始放
        for(int i=30;i>=0;--i)
            if(len&(1<//倍增找,满足就加上
            {
                x=(x+sum[i]*y%mo)%mo;//新增2^i个7
                y=(y*shi[i])%mo;//下次再加就要再往前放2^i位了
            }

        x=(x+(long long)(n-1)*y%mo)%mo;//加上最前面的n-1
        cout<'\n';
    }
    return 0;
}

本题结。

你可能感兴趣的:(倍增法,数学推理,noip,倍增,数学推理)