题目连接: https://ac.nowcoder.com/acm/contest/7079/B
第一种方法: 多个前缀和, 通过i = n-1来得到i = n的情况, 稍显复杂, 公式请自行推导.
第二种方法: 化简, 将上式j, k全部替换成i,
先看最内层: k从 1 到 j , 而i, j不变, 用a(n) = n 的求和公式, 去掉∑之后变成:
∏ ∑ i * j * (1 + j) * j / 2 = ∏ ∑ i * (j ^ 2 + j ^ 3) /2;
然后再去最后一个∑, j 从 1 到 i, 而 i 不变, 这个地方用到的是
a(n) = n ^ 2 和 a(n) = n ^ 3的求和公式(点击跳转),
最后化简得到 :
给的n <= 10 ^ 10 ^ 5, 非常大, 显然, n >= 某个值的时候, 式子 == 0 然后再乘啥东西也是0了, 打表flag记录这个值, 就行了.
注意:
- 乘法逆元, 我将4个式子进行通分后, 直接乘24的逆元方便很多.
- 输入n很大, 10^5位的数字, 要用字符串, 不能用long long啊
- 注意中途不能爆long long! 我改了好久bug, 万万没想到是Pow函数爆了!!! (((φ(◎ロ◎;)φ)))
ps: 数列求和
code:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int mod = 199999;
int n;
ll ijk[200000];
char s[500010];
ll Pow(ll x, int n) {
ll ans = 1;
for (int i = 1; i <= n; i++) {
ans *= x;
ans %= mod;
}
return ans;
}
ll qmi(ll a, ll b, ll p) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
int main() {
cin >> n;
getchar();
int flag;
ijk[0] = 1;
for (int i = 1; i < 2000000; i++) {
ijk[i] = ijk[i - 1] * ((Pow(i, 5) * 3 % mod + Pow(i, 4) * 10 % mod + Pow(i, 3) * 9 % mod + Pow(i, 2) * 2 % mod) * qmi(24, mod - 2, mod) % mod ) % mod;
//乘法逆元
cout << i << ' ' << ijk[i] << '\n';
if (ijk[i] == 0) {
flag = i;
break;
}
}
//cout << flag << '\n';
while (n--) {
//scanf_s("%s", s, 100000); //VS
//scanf("%s", s);
//cout << flag << '\n';
int len = strlen(s);
if (len > 5)
cout << "0\n";
else {
int x = 0;
for (int i = 0; i < len; i++) {
x = x * 10 + (s[i] - '0');
}
//cout << x << " s ";
if (x >= flag) {
cout << '0' << '\n';
}
else
cout << ijk[x] << '\n';
}
}
return 0;
}
2020-9-1, 每一天都有点意思呢