链接:https://ac.nowcoder.com/acm/contest/7079/B
来源:牛客网
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
牛牛最近学习了取模是什么 于是他看到了下面这一道题:
多次询问:每次询问包含一个正整数 nnn 要求你输出下列结果
∏i=1n∑j=1i∑k=1ji×j×k\prod_{i=1}^n \sum_{j=1}^i \sum_{k=1}^j i\times j\times k∏i=1n∑j=1i∑k=1ji×j×k
为了避免结果过大 只需要输出这个式子对 199999199999199999(=2×32×41×271+1=2\times 3^2 \times 41 \times 271+1=2×32×41×271+1,一个质数) 取模的结果。
输入描述:
第一行一个正整数 TTT 表示询问次数。
接下来 TTT 行 每行一个正整数 nnn 含义如上所述
输出描述:
TTT 行非负整数 代表答案。
示例1
输入
复制5 1 2 3 4 5
5
1
2
3
4
5
输出
复制1 14 1050 73001 100955
1
14
1050
73001
100955
说明
n=2 的情况:(1*1*1)*(2*1*1+2*2*1+2*2*2) = 14
备注:
n≤10105n \leq 10^{10^5}n≤10105
保证输入总长度 ≤5×105\leq 5 \times 10^5≤5×105 且 T≤105T \leq 10^5T≤105
个人觉得唯一的难点在于刚开始的化简
关于这个怎么推出来的?我问了几个人,觉得目前能用的方法就是归纳,取n比较小的时候然后找规律去拆拆加加,当然数学好的当我没说。
如果出了这一步,那就预处理后面两个前缀,然后再处理一个连乘的sumi[i].
另外一个trick就是n很大,mod小,所以当n大于模数并且会枚举到mod的时候,后面的模数就都是0了(因为后面的都是模数的倍数)这个trick在多校里也有。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=3e5+100;
const int mod=199999;
typedef long long LL;
LL sumk[mod],sumj[mod],sumi[mod];
char str[maxn];
void solve()
{
cin>>str+1;LL len=strlen(str+1);
if(len>6) cout<<0<<endl;
else
{
LL n=0;
for(LL i=1;i<=strlen(str+1);i++){
n=n*10+str[i]-'0';
}
if(n>=mod) cout<<0<<endl;
else cout<<sumi[n]<<endl;
}
}
int main(void)
{
sumi[0]=1;
for(LL k=1;k<=mod;k++) sumk[k]=(sumk[k-1]%mod+k%mod)%mod;
for(LL j=1;j<=mod;j++) sumj[j]=(sumj[j-1]%mod+sumk[j]%mod*j%mod)%mod;
for(LL i=1;i<=mod;i++) sumi[i]=(sumi[i-1]%mod*i%mod*sumj[i]%mod)%mod;
LL t;cin>>t;
while(t--)
{
solve();
}
return 0;
}