zoukankan      html  css  js  c++  java
  • 【BZOJ2137】submultiple(数论)

    【BZOJ2137】submultiple(数论)

    题面

    BZOJ

    题解

    首先不难发现答案就是:(displaystyleprod_{i=1}^n (sum_{j=1}^{p_i+1}j^k))
    数据范围给定了。
    发现对于(p_i)很小的时候,可以直接用快速幂预处理出来,这样子可以做到(O(n+max(p)*logk))的复杂度。
    对于(p)很大,(k)很小的点,不难知道自然数幂和是一个多项式,带几项进去拉格朗日插值或者第二类斯特林数或者带几项高斯消元或者伯努利数或者打表都行。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MOD 1000000007
    inline ll read()
    {
    	ll x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
    int n,K,mx,ans=1,P[100100];
    namespace Task1
    {
    	int f[100100];
    	void Solve()
    	{
    		for(int i=1;i<=mx;++i)f[i]=(f[i-1]+fpow(i,K))%MOD;
    		for(int i=1;i<=n;++i)ans=1ll*ans*f[P[i]]%MOD;
    	}
    }
    namespace Task2
    {
    	int b[50],a[50],p[50];
    	void pre()
    	{
    		for(int i=1;i<=K+2;++i)p[i]=(p[i-1]+fpow(i,K))%MOD;b[0]=1;
    		for(int i=0;i<=K+1;++i)
    		{
    			for(int j=i+1;j;--j)b[j]=(b[j-1]+MOD-1ll*b[j]*(i+1)%MOD)%MOD;
    			b[0]=1ll*b[0]*(MOD-i-1)%MOD;
    		}
    		for(int i=0;i<=K+1;++i)
    		{
    			int s=p[i+1],inv=fpow(i+1,MOD-2);
    			for(int j=0;j<=K+1;++j)if(i!=j)s=1ll*s*fpow((i-j+MOD)%MOD,MOD-2)%MOD;
    			b[0]=1ll*b[0]*(MOD-inv)%MOD;
    			for(int j=1;j<=K+2;++j)b[j]=(MOD-1ll*(b[j]+MOD-b[j-1])*inv%MOD)%MOD;
    			for(int j=0;j<=K+2;++j)a[j]=(a[j]+1ll*s*b[j])%MOD;
    			for(int j=K+2;j;--j)b[j]=(b[j-1]+MOD-1ll*b[j]*(i+1)%MOD)%MOD;
    			b[0]=1ll*b[0]*(MOD-i-1)%MOD;
    		}
    	}
    	int S(int n)
    	{
    		int ret=0;
    		for(int i=0,nw=1;i<=K+1;++i,nw=1ll*nw*n%MOD)
    			ret=(ret+1ll*a[i]*nw)%MOD;
    		return ret;
    	}
    	void Solve()
    	{
    		pre();
    		for(int i=1;i<=n;++i)ans=1ll*ans*S(P[i])%MOD;
    	}
    }
    int main()
    {
    	n=read();K=read();
    	for(int i=1;i<=n;++i)mx=max(mx,P[i]=read()%MOD+1);
    	if(mx<=100000)Task1::Solve();
    	else Task2::Solve();
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    csharp: Speech
    软件定义网络基础---OF-Config协议
    软件定义网络基础---OpenFlow协议
    软件定义网络基础---南向接口协议概述
    Win10+Ubuntu18.04安装双系统
    软件定义网络基础---OpenFlow流表
    软件定义网络基础---OpenFlow概述
    软件定义网络基础---SDN数据平面
    软件定义网络基础---SDN的核心思想
    软件定义网络基础---SDN的主流构架
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10575466.html
Copyright © 2011-2022 走看看