zoukankan      html  css  js  c++  java
  • atcoder arc106 D Powers

    原题链接:Arc106 D Powers

    题目大意:给定正整数(n,k)以及一数列({a})长度为(n)。对于所有正整数(xin[1,k])求如下表达式$$sumlimits_{1leq l < rleq n}(a_l + a_r) ^ x$$

    数据范围:

    (1 leq n leq 2*10^5)

    (1 leq k leq 300)

    (1 leq a_i leq 10^8)

    思路:不难观察到(n)的范围非常自然的提高到了(2*10^5),但是(k)的范围特别小,(O(nk))是可以承受的复杂度,先可以提取到这个大概的复杂度的信息。其次可以通过式子想到二项式定理进行拆分,对于某个指定的(x),原式等价$$sumlimits_{1leq l < r leq n}sumlimits_{i=0}^x inom{x}{i}a_l^i a_r^{x-i}$$然而遗憾的是这个式子的形式还是非常复杂,由于(1 leq l < r leq n)这个非常丑的式子的存在,导致求和这件事情很难快速得到,但是想当然地,如果这里的限制条件是不存在的,范围是(1 leq l,r leq n)那么求和的表达式可以通过调换求和的顺序变成$$sumlimits_{i=0}xinom{x}{i}sumlimits_{l=1}n a_lisumlimits_{r=1}n a_r^{x-i}$$而式子的后半节是可以通过预处理在(O(nk))的代价下得到的,而系数部分可以通过乘法逆元以(O(N))的代价预处理。两边查询的代价都是(O(1))的。那么只要事情能走到这样对所有元素的求和,就可以化简到一个可以接受的式子。考虑如何拼出整个的求和:如果把原来式子的(l,r)调换得到的式子与原来的式子想加,那么得到的式子就是$$sumlimits_{1leq l,rleq n,l eq r}sumlimits_{i=0}xinom{x}{i}a_lia_r{x-i}$$那么,只需要把整个的部分里挖掉$l=r$的情况,也就是$$sumlimits_{j=1}nsumlimits_{i=0}xa_jia_j{x-i}inom{x}{i}$$接着可以发现后半部分很好合并,调换求和顺序之后得到$sumlimits_{j=1}^na_j^xsumlimits_{i=0}^ninom{x}{i}$根据二项式求和,可以进一步的得到$sumlimits_{j=1}^n(2a_j)^x$。于是可得,两个式子加起来的结果就是$$sumlimits_{i=0}xinom{x}{i}sumlimits_{l=1}na_lisumlimits_{r=1}n{a_r{x-i}}-sumlimits_{j=1}n(2a_j)x$$。回到之前的一步,将(l,r)调换,由于(inom{n}{i} == inom{x}{x-i})于是可以得到两个式子是相等的,即答案=上面的式子的一半。当然,这里题目要求取模,于是要乘乘法逆元。最后分别预处理,最后以(O(k^2))的代价计算所有结果即可。

    代码:

    #define _CRT_SECURE_NO_WARNINGS
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define forn(i,x,n) for(int i = x;i <= n;++i)	
    
    const int N = 2e5+7,M = 305,MOD = 998244353;
    ll fx[M],fc[M],fsa[M],fsb[M];
    int a[N],b[N];
    ll fa[N][M],fb[N][M];
    ll qmul(ll a, ll b, ll P) 
    {
      	ll L = a * (b >> 25LL) % P * (1LL << 25) % P;
      	ll R = a * (b & ((1LL << 25) - 1)) % P;
      	return (L + R) % P;
    }
    ll qpow(ll a,ll b,ll p)
    {
    	ll res = 1 % p;
    	while(b)
    	{
    		if(b & 1)	res = res * a % p;
    		a = a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    ll fact[N],infact[N];
    void init()
    {
        fact[0] = infact[0] = 1;
        for (int i = 1; i < N; i ++ )
        {
            fact[i] = ((ll)fact[i - 1] * i) % MOD;
            infact[i] = ((ll)infact[i - 1] * qpow(i, MOD - 2, MOD)) % MOD;
        }
    }
    ll C(int a,int b)
    {
        return (ll)fact[a]*infact[b]%MOD*infact[a-b]%MOD;
    }
    int main()
    {
    	init();
    	int n,k,rev2 = qpow(2,MOD - 2,MOD);scanf("%d%d",&n,&k);
        forn(i,1,n)	scanf("%d",&a[i]),b[i] = 2 * a[i];
    	fsa[0] = n,fsb[0] = n;
    	forn(i,1,n)
    	{
    		ll _a = 1,_b = 1;	
    		forn(j,1,k)
    		{
    			_a = _a * a[i] % MOD,_b = _b * b[i] % MOD;
    			fsa[j] = (fsa[j] + _a) % MOD,fsb[j] = (fsb[j] + _b) % MOD;
    		}
    	}
        
        forn(x,1,k)
        {
    		ll lf = 0;
    		forn(i,0,x)
    		{
    			ll t = fsa[i] * fsa[x - i] % MOD;
    			t = t * C(x,i) % MOD;
    			lf = (lf + t) % MOD;
    		}
    		// cout << lf << endl;
    		lf = ((lf - fsb[x]) % MOD + MOD) % MOD;
    		printf("%lld
    ",rev2 * lf % MOD);
        }
        return 0;
    }
    
    
  • 相关阅读:
    【POJ 3162】 Walking Race (树形DP-求树上最长路径问题,+单调队列)
    【POJ 2152】 Fire (树形DP)
    【POJ 1741】 Tree (树的点分治)
    【POJ 2486】 Apple Tree (树形DP)
    【HDU 3810】 Magina (01背包,优先队列优化,并查集)
    【SGU 390】Tickets (数位DP)
    【SPOJ 2319】 BIGSEQ
    【SPOJ 1182】 SORTBIT
    【HDU 5456】 Matches Puzzle Game (数位DP)
    【HDU 3652】 B-number (数位DP)
  • 原文地址:https://www.cnblogs.com/HotPants/p/13875052.html
Copyright © 2011-2022 走看看