「SHOI2015」(LOJ2038)超能粒子炮・改

传送门:Here

一句话题意:给定$ t$次询问,每次读入$n,k,$求$ \sum_{i=0}^kC_n^k\ mod\ 2333$,

其中$ t \leq 100000$,$n,k \leq 10^{18},$

前置知识:普通卢卡斯定理 $ C_n^k= C_{n \% p}^{k \% p}*C_{n/p}^{k/p} \% p$

 

我们定义$ S(n,k)=\sum_{i=0}^kC_n^k \% p$

考虑每次询问将式子展开:

$ S(n,k)= \sum\limits_{i=0}^kC_{n/p}^{i/p}*C_{n \%p}^{i \%p}\ mod\ p $

$ =\sum\limits_{i=0}^{k/p-1}C_{n/p}^i* \sum\limits_{j=0}^{p-1}C_{n \%p}^j+ \sum\limits_{i=k/p*p}^kC_{n/p}^{k/p}*C_{n \%p}^{i \%p}$

$ =\sum\limits_{i=0}^{k/p-1}C_{n/p}^i* \sum\limits_{j=0}^{p-1}C_{n \%p}^j+ \sum\limits_{i=0}^{k \%p}C_{n \%p}^{i}*C_{n/p}^{k/p}$

则有$ S(n,k)=S(n/p,k/p)*S(n \%p,p-1)+S(n \%p,k \%p)*C(n/p,k/p) (mod\ p)$

我们可以预处理$ i,j \leq p的s[i][j]和c[i][j]$

那么对于该式子只要递归做第一项以及用卢卡斯求组合数取模的值即可

 

my code:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rt register int
#define ll long long
#define p 2333
#define r read()
using namespace std;
ll read()
{
    ll x = 0; int ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x;
}
void write(ll y)
{
    if (y > 9) write(y / 10);
    putchar(y % 10 + '0');
}
int i,j,k,m,n,x,y,z;
int c[2335][2335],s[2335][2335];
int C(const ll x,const ll y)
{
    return (x<p)?c[x][y]:C(x/p,y/p)*c[x%p][y%p]%p;
}
int S(const ll n,const ll k)
{
    return (n<p)?s[n][k]:(s[n%p][p-1]*S(n/p,k/p-1)+C(n/p,k/p)*s[n%p][k%p])%p;
}
int main()
{    
    c[0][0]=s[0][0]=1;
    for(rt i=1;i<=p;i++)s[0][i]=1;
    for(rt i=1;i<=p;i++)
    {
        for(rt j=0;j<=i;j++)
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%p,s[i][j]=(s[i][j-1]+c[i][j])%p;
        for(rt j=i+1;j<=p;j++)s[i][j]=s[i][j-1];
    }
    for(rt t=read();t;t--)
    {
        ll n=read(),k=read();
        write(S(n,k)),putchar('\n');
    }
    return 0;
}

 

因为最多只有log层所以单次复杂度为log次Lucas,能轻松通过此题

 

posted @ 2018-05-15 17:49  Kananix  阅读(325)  评论(0编辑  收藏  举报

Contact with me