【组合数+找规律】codeforces 815B - Karen and Test

本文解析了CodeForces上的一道题目,该题要求计算一个特定序列的最终值。通过构建数学模型,利用组合数特性,实现了高效的算法。特别讨论了序列长度为奇数和偶数时的不同情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Link:http://codeforces.com/problemset/problem/815/B

/*
题意: 给出一个n长度的序列,按op +,- 交换得到下一行序列,直到变成一个数字,求这个数字的值。【具体看Note】
题解: 发现在n为偶数时,n-1个数形成的倒三角,是隔个位相加和,其系数为组合数,例n=4时,前三个的倒三角的末端值为a1+a3,若n=6时,前5个倒三角末端值为a1+2a3+a5,同理。那么n=4的末端值是a1a2a3和a2a3a4的倒三角的差值,n=6的末端值是a1a2a3a4a5和a2a3a4a5a6的倒三角的和值,所以分类n%4==0 和n%4 == 1。
那n为奇数时,先算一层,其实符号还是从正开始的,在依上计算。特判n=1,n=2,n=3。
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N = 200005;
const int mod = 1e9+7;
LL a[N];
LL powz[N],inv[N],powinv[N];

void init(){
    powz[0] = 0; powz[1] = 1;
    inv[0] = 0; inv[1] = 1;
    powinv[0] = 0; powinv[1] = 1;
    for(int i = 2; i < N; i++){
        powz[i] = (powz[i-1]*(LL)i)%mod;
        inv[i] = inv[mod%i]*(mod-mod/i)%mod;
        powinv[i] = powinv[i-1]*inv[i]%mod;
    }
}
LL C(int x, int y){
    if(x == 0 || x == y)    return 1LL;
    return powz[y]*powinv[y-x]%mod*powinv[x]%mod;
}


int main(){
    init();
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
        scanf("%I64d",&a[i]);
    if(n == 1){
        printf("%I64d\n",a[1]);
        return 0;
    }
    if(n&1){
        LL pre = a[1];
        LL op = 1;
        for(int i = 2; i <= n; i++){
            a[i-1] = (pre+op*a[i]+mod)%mod;
            pre = a[i];
            op *= -1;
        }
        n--;
    }
    if(n == 2){
        printf("%I64d\n",(a[1]+a[2])%mod);
        return 0;
    }
    int ff = n/2-1;
    LL ans1 = 0, ans2 = 0;
    int k = 0, flag = 0;
    for(int i = 1; i <= n; i+=2){
        ans1 = (ans1+a[i]*C(k,ff)%mod)%mod;
        if(k == ff)
            flag = 1;
        if(flag)
            k--;
        else
            k++;
    }
    k = 0 , flag = 0;
    for(int i = 2; i <= n; i+=2){
        ans2 = (ans2+a[i]*C(k,ff)%mod)%mod;
        if(k == ff)
            flag = 1;
        if(flag)
            k--;
        else
            k++;
    }
    if(n%4 == 0){
        printf("%I64d\n",(ans1-ans2+mod)%mod);
    }
    else{
        printf("%I64d\n",(ans1+ans2)%mod);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值