Karen and Test

原题:Karen and Test

原题大意

n个正整数排成一行,每相邻两个数进行加或减操作:第一第二个数相加,第二第三个数相减,第三第四个数相加,第四第五个数相减……,得到的结果排成第二行,然后继续这样的操作,并且初始的前两个数是加还是减,与上一行最后两个数的操作符相反,问最后得到的结果是多少?

算法分析

考虑最简版本每个ai对最终式子的贡献,可以令ai的系数为1,其余为0,类似0,0,0…1…0,0,0,同时暂且不考虑减法,可以得出每个ai的贡献为C(n-1,k-1) ,然后通过下面这个过程,可以看出最终的式子,是两个奇偶序列和(最简版本),相加或做差得到的,n mod 4 = 2时相加,n mod 4 = 0时做差。(如果n是奇数,那么先暴力进行第一次变换使得n成为偶数)

程序代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const ll maxn = 200000+5;
ll fac[maxn], inv[maxn];//fac[i] 保存阶乘,inv[i] 保存fac[i]的逆元
ll a[maxn];
ll ans;
int n;
void add(ll &a, ll b){
    a += b;
    if(a >= mod) a -= mod;
}
//快速幂
ll pow_mod(ll a, ll p){
    ll ans = 1;
    while(p){
        if(p & 1) ans = ans * a % mod;
        a = a * a % mod;
        p >>= 1;
    }
    return ans;
}

//组合计算公式
ll C(int n, int k){
    return (fac[n] * inv[k] % mod )* inv[n-k] % mod;
}

int main(){
//freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    fac[0] = 1;
    for(int i = 1; i < maxn; i++) fac[i] = fac[i-1] * i % mod;
    inv[maxn-1] = pow_mod(fac[maxn-1],mod-2);
    for(int i = maxn - 2; i >=0; i--) inv[i] = inv[i+1] * (i+1) % mod;
    cin >> n;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    if(n&1){
        if(n == 1) {cout << a[1] << endl; return 0;}
        int sign = 1;
        for(int i = 1; i < n; i++){
            a[i] = (a[i]+sign*a[i+1] + mod) %mod;
            sign*=-1;
        }
        n--;
    }
    ll sum1 = 0LL, sum2 = 0LL;
    for(int i = 1; i <= n; i++){
        if(i&1) add(sum1, C(n/2-1, i/2) * a[i]%mod);
        else add(sum2, C(n/2-1, i/2-1) * a[i]%mod);
    }
    if(n%4 != 0) cout << (sum1 + sum2) % mod << endl;
    else cout << (sum1 - sum2 + mod) % mod << endl;
    return 0;
}