zoukankan      html  css  js  c++  java
  • luogu P4593 [TJOI2018]教科书般的亵渎

    这是个求自然数幂和的模板题。难点在于理解题意。

    很容易发现 (k=m+1),然后就是 (O(k^2)) 的累计答案。

    加上插值求自然数幂和,总复杂度为 (O(k^3))

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define int long long
    
    using namespace std;
    
    typedef long long LL;
    const int N=60,M=1000000007,K=1000000;
    int m,A[K+9],p[K],cnt,d[K+9];
    LL n,a[N],k,pre[K],suf[K],fac[K],inv_fac[K];
    
    int ksm(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=1ll*res*a%M;
    		b>>=1,a=1ll*a*a%M;
    	}
    	return res;
    }
    
    void prework(int k)
    {
    	d[1]=1,cnt=0;
    	for (int i=2;i<=k+2;i++)
    		A[i]=0; 
    	for (int i=2;i<=k+2;i++)
    	{
    		if(!A[i])
    			A[i]=i,p[++cnt]=i,d[i]=ksm(i,k);
    		for (int j=1;j<=cnt;j++)
    		{
    			if(p[j]>A[i]||p[j]>(k+2)/i)
    				break;
    			A[p[j]*i]=p[j];
    			d[p[j]*i]=1ll*d[p[j]]*d[i]%M;
    		}
    	}
    //	printf("%d
    ",k+2);
    //	for (int i=1;i<=k+2;i++)
    //		printf("%d ",d[i]);puts("");
    	for (int i=2;i<=k+2;i++)
    		d[i]=(d[i]+d[i-1])%M;
    }
    
    void init()
    {
    	scanf("%lld %lld",&n,&m);
    	for (int i=1;i<=m;i++)
    		scanf("%lld",&a[i]);
    	sort(a+1,a+1+m);
    	k=m+1;
    }
    
    int Get_Sum(LL n,int k)
    {
    	prework(k);
    	pre[0]=1;
    	for (int i=1;i<=k+2;i++)
    		pre[i]=1ll*pre[i-1]*((n-i)%M)%M;
    	suf[k+3]=1;
    	for (int i=k+2;i>=1;i--)
    		suf[i]=1ll*suf[i+1]*((n-i)%M)%M;
    	fac[0]=1;
    	for (int i=1;i<=k+2;i++)
    		fac[i]=1ll*fac[i-1]*i%M;
    	inv_fac[k+2]=ksm(fac[k+2],M-2);
    	for (int i=k+1;i>=0;i--)
    		inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%M;
    	int ans=0;
    	for (int i=1;i<=k+2;i++)
    		ans=(ans+d[i]*pre[i-1]%M*suf[i+1]%M*inv_fac[i-1]%M*inv_fac[k+2-i]%M*(k+2-i&1?-1:1))%M;
    	return ans;
    }
    
    void work()
    {
    	LL ans=0;
    	a[++m]=n+1;
    	for (int i=0;i<=m;i++)
    		for (int j=i+1;j<=m;j++)
    			ans=(ans+(Get_Sum(a[j]-1-a[i],k)-Get_Sum(a[j-1]-a[i],k))%M)%M;
    	printf("%lld
    ",(ans+M)%M);
    }
    
    signed main()
    {
    	int T;
    	scanf("%lld",&T);
    	while(T--)
    	{
    		init();
    		work();
    	}
    	return 0;
    }
    
  • 相关阅读:
    BZOJ4644 经典傻逼题 (线段树分治+可撤销线性基+Xor)
    CF678E Another Sith Tournament(思维+dp)
    HDU 6511
    HDU6513 Reverse It(容斥+Cnk)
    一篇最浅显易懂的Splay讲解(试问谁能比我的更易懂
    [CTSC2016]时空旅行 (线段树分治+凸壳
    关于dsu on tree 和一些例题 CF 741 D
    关于区间开根号+区间询问
    [FJOI2015]火星商店问题 --线段树分治+可持久化trie
    线段树 关于pushup的技巧
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13460580.html
Copyright © 2011-2022 走看看