【Kickstart】2018 Round C - Kickstart Alarm

解法

就是数学优化+快速幂+除法取模结合在一起
首先,数学优化比较容易,最后肯定是要变成每遍历一个数就加一次。对于 a m a_m am,它可以是子数组里的第1,2,…,m个,而它是第i个的子数组一共有 ( N + 1 − m ) (N+1-m) (N+1m)个,当计算 P O W E R j {POWER}_j POWERj时,它的系数就是 1 j 1^j 1j 2 j 2^j 2j 3 j 3^j 3j,…, m j m^j mj,所以最后 a m a_m am的系数为:
∑ j = 1 k ∑ i = 1 m ( N + 1 − m ) i j = ( N + 1 − m ) ∑ i = 1 m ∑ j = 1 k i j = ( N + 1 − m ) ∑ i = 1 m i ( i k − 1 ) i − 1 \sum_{j=1}^k\sum_{i=1}^m(N+1-m)i^j\\ =(N+1-m)\sum_{i=1}^m\sum_{j=1}^ki^j\\ =(N+1-m)\sum_{i=1}^m\frac{i(i^k-1)}{i-1} j=1ki=1m(N+1m)ij=(N+1m)i=1mj=1kij=(N+1m)i=1mi1i(ik1)

然后,显然对于 i k i^k ik那部分我们需要用快速幂来求

最后,对于 i ( i k − 1 ) i − 1 ( m o d   p ) \frac{i(i^k-1)}{i-1}(mod\ p) i1i(ik1)(mod p),它不能通过分子和分母都分别取余来求。
这里要用到费马小定理:

如果 a a a p p p互质,那么 a p − 1 ( m o d   p ) = 1 a^{p-1}(mod\ p)=1 ap1(mod p)=1

p = 1 0 9 + 7 p=10^9+7 p=109+7,它是个质数,那么有 ( i − 1 ) p − 1 ( m o d   p ) = 1 (i-1)^{p-1}(mod\ p)=1 (i1)p1(mod p)=1
所以 i ( i k − 1 ) ( i − 1 ) p − 2 ( m o d   p ) = i ( i k − 1 ) i − 1 ( m o d   p ) i(i^k-1)(i-1)^{p-2}(mod\ p)=\frac{i(i^k-1)}{i-1}(mod\ p) i(ik1)(i1)p2(mod p)=i1i(ik1)(mod p)
这样就可以分别算出每个因子mod p的值再相乘了

最后, ∑ i = 1 m \sum_{i=1}^m i=1m算是一个前缀和,所以可以不用每次都循环

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MASK 0x10000
#define MAXN 16

using namespace std;

typedef long long lld;

const lld MOD = pow(10,9)+7;

lld FAST_POW(int i, int k) {
    lld base = i, res = 1;
    int e = k;
    while (e>0) {
        if(e&1) res = res*base%MOD;
        base = base*base%MOD;
        e = e>>1;
    }
    return res;
}

lld POW(int i,int k) {
    if (i==1) return k;
    else {
        lld A = (i*(FAST_POW(i,k)-1))%MOD, B =  FAST_POW(i-1,MOD-2);
        return A*B%MOD;
    }
}

int main() {
    int t;
    scanf("%d",&t);
    for(auto round=1;round<=t;++round) {
        lld n,k,x,y,c,d,e1,e2,f;
        scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld",&n,&k,&x,&y,&c,&d,&e1,&e2,&f);
        lld a = (x+y)%f;
        lld ans = n*k*a%MOD;
        lld cumprod = POW(1,k);
        for(int i=1;i<n;++i) {
            lld tmp = x;
            x = (c*x+d*y+e1)%f;
            y = (d*tmp+c*y+e2)%f;
            a = (x+y)%f;
            cumprod = (cumprod+POW(i+1,k))%MOD;
            ans = (ans + cumprod*a% MOD*(n-i)% MOD)% MOD;
        }
        printf("Case #%d: %lld\n",round,ans%MOD);
    }
}

你可能感兴趣的:(Kickstart)