jzoj 4819. 【NOIP2016提高A组模拟10.15】算循环 数学+逆元

来源:互联网 发布:巨人网络借壳上市方案 编辑:程序博客网 时间:2024/06/11 02:10

题意:给出n和m的值,要求计算tmp的值是多少。

for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            for (int k=i;k<=n;k++)                for (int l=j;l<=m;l++)                    for (int x=i;x<=k;x++)                        for (int y=j;y<=l;y++) tmp++;

n,m<=1018

分析:把题目抽象成一个n*m的矩阵,那么每个点(i,j)被计算的次数就是i*j*(n-i+1)*(m+j-1)
那么答案就是ni=1mj=1ij(ni+1)(mj+1)
然后我们可以先O(n)预处理出w=ni=1i(ni+1)
那么就可以O(n)枚举j然后求出答案。
我们发现把把上面式子展开后就变成了ni=1in+ii+i
我们发现ni=1in=n2(n+1)/2
ni=1ii=n(n+1)(2n+1)/6
那么就可以O(1)求出w,同理也可以用O(1)的时间复杂度把答案给求出来。

代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define MOD 1000000007#define ll long longusing namespace std;int ksm(int x,int y){    if (!y) return 1;    if (y==1) return x;    int w=ksm(x,y/2);    w=(ll)w*w%MOD;    if (y%2==1) w=(ll)w*x%MOD;    return w;}int main(){    freopen("loop.in","r",stdin);    freopen("loop.out","w",stdout);    ll n,m;    scanf("%lld%lld",&n,&m);    n%=MOD;m%=MOD;    ll w=(ll)n*n%MOD*(n+1)%MOD*ksm(2,MOD-2)-(ll)n*(n+1)%MOD*((n*2+1)%MOD)%MOD*ksm(6,MOD-2)%MOD+(ll)n*(n+1)%MOD*ksm(2,MOD-2)%MOD;    w=(w%MOD+MOD)%MOD;    ll ans=(ll)m*(m+1)%MOD*m%MOD*w%MOD*ksm(2,MOD-2)%MOD-m*(m+1)%MOD*((2*m+1)%MOD)%MOD*w%MOD*ksm(6,MOD-2)%MOD+w*m%MOD*(m+1)%MOD*ksm(2,MOD-2)%MOD;    ans=(ans%MOD+MOD)%MOD;    printf("%lld",ans);    return 0;}
0 0
原创粉丝点击