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% 的数据:
n≤5
。
对于另 20% 的数据:
∑n≤107
。
对于另 20% 的数据:
T=1
。
对于 100% 的数据:
T≤5∗105;n≤109
。
分析:表示看到n竟然有
109
,吓傻。然后去找规律,还真有(因为偶数项被bool判断掉了,我就只找了奇数项的规律,第一个数是n,第二个数是答案,第三个数是取模后):
然后就误入歧途,开始疯狂找取模后的规律(每次加的数都不一样怎么可能有规律……)。但找到的这种头几位是n-1中间夹(n-1)/2个7末尾9的规律对正解很有帮助,
109
只能log出答案,qianguch想到了倍增(真TM是个天才!)!用数组存
21−30
个7的这种数的答案,就可以log求解了。
(其实我更纠结于取了模还可以正常运算吗,事实证明加、减、乘都是可以的)
然而真正的正解是用到了NOI知识的,因为233333不是质数,要求逆元,由于我写的是NOIP的总结,就不说了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
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<<i))//倍增找,满足就加上
{
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<<x<<'\n';
}
return 0;
}
本题结。