Problem C. Kickstart Alarm Google Kickstart Round C 2018

这一题把公式拆开是可以找到规律的。我开始找出了固定i-th exponential-power,得到一个很冗长的公式,再对i求和。然而大数据并不能算出来。。

另一个角度是针对每个A[i],观察其贡献的值、

对于数组[a,b,c,d,e],a作为sub array的第一个元素总计5次,b作为sub array的第一个元素总计4次,c作为sub array的第一个元素总计3次,对应的贡献是A[i]*(1^1+1^2+...+1^K)

b作为sub array的第2个元素总计4次,c作为sub array的第一个元素总计3次,…对应的贡献是A[i]*(2^1+2^2+...+2^K)

由此可以得出,A[i]的贡献是

A[i]*(N-i+1)*(geo_sum(i,K)+geo_sum(2,K)+...+geo_sum(i,K)), geo_sum(x,K)=x+x^2+x^3+...+x^K

最终结果对所有的A[i]求和即可。

等比数列a1,a2,..an, an=a1*q^(n-1)求和Sn=(a1*(1-q^n))/(1-q)=x(x^K-1)/(x-1)。除法不能直接mod,需要先算出逆序数,i.e., if P is prime, (1/a)%P=a^(P-2)。

另外取模的时候有很多坑。。

1. 如果用(x^(K+1)%mod-x)*inv[x-1]%mod,x^(K+1)%mod-x是有可能<0的,所以要判断中间结果是否<0,如果<0就先+mod再乘后面的数。

2. 对于a*b*c % mod这样的连乘,一定要在每一个相乘的项后面取mod,否则很可能中途就overflow了。比如我开始写成了((a%mod)*(b%mod)*(c%mod))%mod就一直incorrect,应该是(((a*b)%mod)*c)%mod。

另外sum of geo_sum是随着i递增的,不需要对于每个A[i]都重新算,直接累加A[i]对应的贡献值即可。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
//Problem C. Kickstart Alarm Kickstart 2018 round C
const int maxn=1000010;
int N;
int T;
long long C;
int K;
long long D;
long long F;
long long E1;
long long E2;
long long x1;
long long y1;
long long A[maxn];
const long long mod=1000000007;
long long presum[maxn];
long long inv[maxn];//1/a % mod=a^(p-2)
long long ans;
long long pow_mod(long long a,long long b)
{
    long long s=1;
    long long t=1;
    while(b)
    {
        if(b&t)
        {
            s=(s*a)%mod;
        }
        a=(a*a)%mod;
        b=b>>1;
    }
    return s;
}
long long power_sum(long long x)
{
    if(x==1)
    {
        return (long long)K;
    }
    else
    {
        long long ret=((x*((pow_mod(x,K)-1)%mod)%mod)*inv[x-1])%mod;//need to mod after each production, avoid overflow
        if(ret<0)//why this can happen? if use pow_mod(x,K+1)-x, pow_mod(x,K+1)-x is after mod, may be less than x
        {
            cout<<(pow_mod(x,K)-1)<<" "<<x<<" "<<inv[x-1]<<endl;
            ret+=mod;
        }
        return ret;
    }
}
int main()
{
//    freopen("input.txt","r",stdin);
    freopen("C-large-practice.in","r",stdin);
    freopen("C.txt","w",stdout);
    cin>>T;
    for(int i=1;i<=1000010;i++)
    {
        inv[i]=pow_mod(i,mod-2)%mod;
    }
    for(int ca=1;ca<=T;ca++)
    {
        scanf("%d %d %lld %lld %lld %lld %lld %lld %lld", &N, &K, &x1, &y1, &C, &D, &E1, &E2, &F);
        memset(A,0,sizeof(A));
        ans=0;
        A[1]=(x1+y1)%F;
        for(int i=2;i<=N;i++)
        {
            int prex1=x1;
            int prey1=y1;
            x1=(C*prex1+D*prey1+E1)%F;
            y1=(D*prex1+C*prey1+E2)%F;
            A[i]=(x1+y1)%F;
        }
//        for(int i=1;i<=N;i++)
//        {
//            presum[i]=presum[i-1]+A[i];
//        }
        long long geo_sum=0;
        for(int i=1;i<=N;i++)
        {
//            if(power_sum(i)<0)
//            {
//                cout<<"here"<<endl;
//            }
            geo_sum+=power_sum(i);
            geo_sum%=mod;
            ans+=((A[i]*(N-i+1)%mod)*geo_sum)%mod;//previous forgot to mod after the first production, use (A[i]*(N-i+1)*geo_sum)%mod, cause error, may be overflow
            ans%=mod;
        }
//        for(int l=1;l<=N;l++)
//        {
//            for(int x=1;x<=l;x++)
//            {
//                ans+=(power_sum(x)%mod)*(presum[N-l+x]-presum[x-1])%mod;
//                ans%=mod;
//            }
//        }
//        for(int i=0;i<N;i++)
//        {
//            cout<<A[i]<<" ";
//        }
//        cout<<endl;
//        for(int k=0;k<K;k++)
//        {
//            //cout<<"k "<<k+1<<endl;
//            for(int i=1;i<=N;i++)
//            {
//                for(int j=i+1;j<=N;j++)//A[i,..,j-1]
//                {
//                    for(int l=i;l<j;l++)
//                    {
//                        long long a=l-i+1;
//                        long long b=k+1;
//                        //cout<<"a "<<a<<" b "<<b<<" "<<pow_mod(a,b)<<endl;
//                        long long tmp=A[l]*pow_mod(a,b)%mod;
//                        //cout<<"i "<<i<<" j "<<j<<" l "<<l<<" A[l] "<<A[l]<<" tmp "<<tmp<<endl;
//                        power[k]+=tmp;
//                        power[k]%=mod;
//                    }
//                }
//            }
//        }
//        for(int i=0;i<K;i++)
        printf("Case #%d: %d\n", ca, ans);
        cerr<<"case "<<ca<<endl;

    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值