Codeforces 1629 F2. Game on Sum (Hard Version) —— 杨辉三角,暴力,找规律

This way

题意:

你手上有一个数字,一开始是0,每次可以选择[0,k]中任意一个实数。然后由对手决定加还是减去这个数字。总共n轮,并且对手至少要有m轮加上你手中的数字。你希望数字尽可能大,对手希望数字尽可能小。如果你们双方都做出最优抉择,问数字最大是多少。

题解:

有了上题的基础就比较好做了。
观察数据往往能给出思路,看到是1e6,就说明有暴力可能,否则不就给出1e9了吗。
画一下图:

Codeforces 1629 F2. Game on Sum (Hard Version) —— 杨辉三角,暴力,找规律_第1张图片
假设下面红点是要求的值,我们将它所对应的关系画出来:

Codeforces 1629 F2. Game on Sum (Hard Version) —— 杨辉三角,暴力,找规律_第2张图片
看到这个右上斜的这里,1,3,6,10是否有点眼熟呢。
我们可以看到位于(7,4)。
再多画一些图就可以看到是跟n-m-1有关。列一下就可以发现是这样一个公式:

for(ll i=m,j=n-m-1;i>=1;i--,j++)
    ans=(ans+i*fac2[i-1]%mod*c(j,n-m-1))%mod;
#include
using namespace std;
const int N=1e6+5;
#define ll long long
const ll mod=1e9+7;
ll qpow(ll a,ll b){ll ans=1;for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;return ans;}
ll fac[N],inv[N],fac2[N],inv2[N];
ll c(ll n,ll m){
    if(m<0||m>n)return 0;
    if(n==m||m==0)return 1;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
    fac[1]=1;
    for(int i=2;i<N;i++)fac[i]=fac[i-1]*i%mod;
    inv[N-1]=qpow(fac[N-1],mod-2);
    for(int i=N-2;i;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
    inv2[0]=1,fac2[0]=1;
    for(ll i=1;i<N;i++)fac2[i]=fac2[i-1]*2%mod,inv2[i]=qpow(fac2[i],mod-2);
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        if(n==m){
            printf("%lld\n",1ll*n*k%mod);
            continue;
        }
        ll ans=0;
        for(ll i=m,j=n-m-1;i>=1;i--,j++)
            ans=(ans+i*fac2[i-1]%mod*c(j,n-m-1))%mod;
        printf("%lld\n",ans*k%mod*inv2[n-1]%mod);
    }
    return 0;
}

你可能感兴趣的:(想法,数学,leetcode,算法,职场和发展)