题解 P3169 【[CQOI2015]多项式 】
waaadreamer · · 题解
这道题应该上来就能看出来a肯定是个有循环节的玩意儿……结果我上来打了个表瞄了一眼,以为循环节长度就是3389(我真的太菜了),然后无限WA……后来才发现原来循环节长度是3388……Orz……
于是就可以开始推算式了,考虑展开:
显然可以交换求和顺序,于是乎
然后就得到了
这是一个裸的二项式反演,于是就可以得到
然后发现题目中的条件
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1 << 15 | 5;
const double PI = acos(-1);
struct C{
double x, y;
C operator+(const C &c) const {return (C){x + c.x, y + c.y};}
C operator-(const C &c) const {return (C){x - c.x, y - c.y};}
C operator*(const C &c) const {return (C){x * c.x - y * c.y, x * c.y + y * c.x};}
} aa[maxn], tab[maxn];
void rader(C *a, int n){
for(int i = 1, j = n >> 1; i < n - 1; i++){
if(i < j) swap(a[i], a[j]);
int k = n >> 1;
for(; j >= k; k >>= 1) j -= k;
if(j < k) j += k;
}
}
void fft(C *a, int n){
rader(a, n);
for(int h = 2; h <= n; h <<= 1){
int hh = h >> 1;
for(int i = 0; i < n; i += h)
for(int j = i; j < i + hh; j++){
C x = a[j], y = a[j + hh] * tab[n / h * (j - i)];
a[j] = x + y, a[j + hh] = x - y;
}
}
}
struct Bigint{
int a[maxn], n;
Bigint(){memset(a, 0, sizeof(a)); n = 0;}
Bigint(char *str){
memset(a, 0, sizeof(a));
int l = strlen(str);
n = 0;
for(int i = l - 1; i >= 0; i -= 4, ++n){
for(int j = max(i - 3, 0); j <= i; j++)
a[n] = a[n] * 10 + str[j] - '0';
}
}
Bigint operator*(const Bigint &b) const {
Bigint res = Bigint();
for(res.n = 1; res.n < n + b.n; res.n <<= 1);
for(int i = 0; i < res.n; i++){
aa[i] = (C){a[i], b.a[i]};
tab[i] = (C){cos(2 * i * PI / res.n), sin(2 * i * PI / res.n)};
}
fft(aa, res.n);
for(int i = 0; i < res.n; i++){
aa[i] = aa[i] * aa[i];
tab[i].y = -tab[i].y;
}
fft(aa, res.n);
for(int i = 0; i < res.n; i++) aa[i].y /= 2 * res.n;
for(int i = 0; i < res.n; i++){
ll t = (ll)(aa[i].y + 0.5);
res.a[i] = t % 10000;
aa[i + 1].y += t / 10000;
}
if(aa[res.n].y > 0.5) res.a[res.n++] = (int)(aa[res.n].y + 0.5);
while(res.n > 0 && !res.a[res.n - 1]) --res.n;
return res;
}
Bigint operator+(const Bigint &b) const {
Bigint res = Bigint();
res.n = max(n, b.n);
for(int i = 0; i < res.n; i++){
res.a[i] += a[i] + b.a[i];
if(res.a[i] >= 10000) ++res.a[i + 1], res.a[i] -= 10000;
}
if(res.a[res.n]) ++res.n;
return res;
}
Bigint operator*(int b) const {
Bigint res = Bigint();
for(int i = 0; i < n; i++){
ll t = (ll)a[i] * b + res.a[i];
res.a[i] = t % 10000;
res.a[i + 1] = t / 10000;
}
for(res.n = n; res.a[res.n]; ++res.n){
res.a[res.n + 1] = res.a[res.n] / 10000;
res.a[res.n] %= 10000;
}
return res;
}
Bigint operator/(int b) const {
Bigint res = Bigint();
res.n = n;
for(int i = n - 1; i >= 0; i--){
int t = res.a[i] + a[i];
if(i > 0) res.a[i - 1] += t % b * 10000;
res.a[i] = t / b;
}
while(res.n > 0 && !res.a[res.n - 1]) --res.n;
return res;
}
int operator%(int b) const {
int res = 0;
for(int i = n - 1; i >= 0; i--)
res = (res * 10000 + a[i]) % b;
return res;
}
Bigint operator-(const Bigint &b) const {
Bigint res = Bigint();
for(int i = 0; i < n; i++){
res.a[i] += a[i] - b.a[i];
if(res.a[i] < 0) res.a[i] += 10000, --res.a[i + 1];
}
for(res.n = n; res.n > 0 && !res.a[res.n - 1]; --res.n);
return res;
}
Bigint& operator++(){
++a[0];
for(int i = 0; i < n; i++){
if(a[i] >= 10000) ++a[i + 1], a[i] -= 10000;
else break;
}
if(a[n]) ++n;
return *this;
}
void print(){
printf("%d", a[n - 1]);
for(int i = n - 2; i >= 0; i--) printf("%04d", a[i]);
putchar('\n');
}
int cmp(const Bigint &b) const {
if(n != b.n) return n < b.n ? -1 : 1;
for(int i = n - 1; i >= 0; i--)
if(a[i] != b.a[i]) return a[i] < b.a[i] ? -1 : 1;
return 0;
}
bool operator>=(const Bigint &b) const {return cmp(b) >= 0;}
} n, m, mul, res;
char str[maxn];
int a[3500], vis[3500], K;
int main(){
vis[a[0] = 1] = 1;
for(int i = 1; i < 3388; i++)
a[i] = (1234 * a[i - 1] + 5678) % 3389;
scanf("%s", str);
n = Bigint(str);
scanf("%d", &K);
scanf("%s", str);
m = Bigint(str);
int sub = (n - m).a[0], mod = m % 3388;
mul.n = mul.a[0] = 1;
for(int i = 0; i <= sub; i++){
res = res + mul * a[mod];
mul = mul * (++m) * K / (i + 1);
mod = (mod + 1) % 3388;
}
res.print();
return 0;
}