• bzoj3142[HNOI2013]数列


    五分钟就推完了...
    如果模数为质数还有一些简单的搞法,不是质数我好像只想到这一种简便一点的。
    枚举每天与前一天的差值,第一天有 n-差值之和 的取法:

    [sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{k-1}=1}^M (N-sum_{i=1}^{k-1}x_i) ]

    [ans=M^{k-1}*N-sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{k-1}=1}^M(sum_{i=1}^{k-1} x_i) ]

    (g(i)=sum_{x_1=1}^M sum_{x_2=1}^M ... sum_{x_{i}=1}^M (sum_{j=1}^i x_i))
    g是可以递推的。

    [g(i)=sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M sum_{x_{i}=1}^M (x_1+...+x_{i-1}+x_i) ]

    [=sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M(M*sum_{j=1}^{i-1}x_j+sum_{x_i=1}^M x_i) ]

    [=M*sum_{x_1=1}^M ...sum_{x_{i-1}=1}^M (sum_{j=1}^{i-1}x_j) + M^{i-1}*frac{M*(M+1)}{2} ]

    [=M*g(i-1)+M^{i-1}*frac{M*(M+1)}{2} ]

    首先(g(1)=frac{M*(M+1)}{2},g(2)=2*M*frac{M*(M+1)}{2}),我们会去猜想(g(k)=k*M^{k-1}*frac{M*(M+1)}{2})
    然后就是简单的用数学归纳法证明了,假设我们知道了对于(i=k)时成立,有(g(k)=k*M^{k-1}*frac{M*(M+1)}{2}),那么(g(k+1)=M*g(k)+M^k*frac{M*(M+1)}{2}=k*M^k*frac{M*(M+1)}{2}+M^k*frac{M*(M+1)}{2}=(k+1)*M^k*frac{M*(M+1)}{2}),所以对于任意(iin N^{*}),猜想成立。
    (当然也可以得到(frac{g(i)}{M^i}=frac{g(i-1)}{M^{i-1}}+frac{(M+1)}{2})就可以直接算通项了)
    所以答案就是

    [M^{k-1}*N-g(k-1) ]

    [=M^{k-1}*N-(k-1)*M^{k-2}*frac{M*(M+1)}{2} ]

    特判一下(k=1)的情况。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define pl puts("lala")
    #define cp cerr<<"lala"<<endl
    #define fi first
    #define se second
    #define pb push_back
    #define ln putchar('
    ')
    using namespace std;
    inline int read()
    {
    	char ch=getchar();int g=1,re=0;
    	while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
    	return re*g;
    }
    typedef long long ll;
    typedef pair<int,int> pii;
    
    int mod;
    ll qpow(ll a,int n)
    {
    	ll ans=1;
    	for(;n;n>>=1,a=a*a%mod) if(n&1) ans=ans*a%mod;
    	return ans;
    }
    ll n;
    int m,k;
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    #endif
    	scanf("%lld%d%d%d",&n,&k,&m,&mod);
    	n%=mod;
    	if(k==1) printf("%lld
    ",n);
    	else printf("%lld
    ",(qpow(m,k-1)*n%mod
    	-1ll*m*(m+1)/2%mod*(k-1)%mod*qpow(m,k-2)%mod+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    Word操作——通配符
    圆的拟合
    最优化案例整理
    机器学习数学基础知识备忘
    scikit-learn学习笔记
    Linux下安装scikit-learn
    ROS学习备忘
    [ROS]激光驱动安装
    CMake和Linux编程:find_package的使用
    [OpenCV]直线拟合
  • 原文地址:https://www.cnblogs.com/thkkk/p/8721862.html
Copyright © 2020-2023  润新知