zoukankan      html  css  js  c++  java
  • 国家—(分治)

    【题目描述】

    给定正整数 n , p 和非负整数 a , b ,求 an+an-1b+an-2b2+…+a2bn-2+abn-1+bn,例如当n=1时,该结果等于 a+b 。由于答案可能很大,请对 p 取模。

    【输入格式】

    ▲多组数据

    第一行,一个正整数T,表示数据组数。

    接下来 T 行,每行四个整数 n , a , b , p ,表示一组数据,相邻两个数之间有空格隔开。

    【输出格式】

    共 T 行,每行一个非负整数,表示一组数据的答案。

    【样例输入】

    3

    2 3 3 233

    5 1 2 100

    1000 233 666 998244353

    【样例输出】

    27

    63

    952904376

    【数据规模及约定

    对于30%的数据,满足 T≤10,n,a,b≤106p=109+7。

    对于60%的数据,满足 T≤10,000,n,a,b≤109p=109+7。

    另有10%的数据,满足 a=0。

    另有10%的数据,满足 a=1。

    对于100%的数据,满足 T≤30,000,n,a,b,p≤1012

    思路:

      可以采取分治来求解。

      先从简单入手: 如:

      当 n=5 时,有: a5+a4b+a3b2+a2b3+ab4+b→ 可以将序列从中间分为 a5+a4b+a3b2  和 a2b3+ab4+b5

      那么从中提出 a3 和 b3 可得:a3( a2+ab+b) + b3( a2+ab+b) →又可以合并为 ( a3+b) × ( a2+ab+b)。

      后面的式子还可以继续分治: 可以看作是 n=2 时所要求的式子。

      但这时,n 为偶数,式子是一个三项式,无法从中间直接分解。则考虑添项:a2+ab+b= a2+ab+ab+b2-ab 。

      最终为:(a+b)(a+b)-ab 。

      所以 a5+a4b+a3b2+a2b3+ab4+b= ( a3+b) × ( (a+b)(a+b)-ab )。

    从上述简单的求解可以看出:

      当 n 为奇数时,可以将式子直接二分递归下去(dfs(n>>1)),当 n 为奇数时,将式子添项后再二分递归(dfs((n>>1)+1)-ksm((a*b),(n>>1))) 奇数 n 的 -ksm((a*b),(n>>1)) 是减去中间添加的项。

    代码实现:  

    long long dfs(long long k)//k,此时的二分 n 的值
    {
      if(k==1) return (a+b)%p;
      if(k&1) return ksc( ( ksm(a,(k>>1)+1,p)+ksm(b,(k>>1)+1,p) )%p , dfs(k>>1) ,p)%p;// n 为奇数
      return ( ksc( ( ksm(a,k>>1,p)+ksm(b,k>>1,p) )%p , dfs(k>>1) ,p)%p + ( p - ksm(ksc(a,b,p),k>>1,p) ) )%p;
    }//ksc 为O(1)快速乘,ksm 为快速幂,p 为模数

    完整代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<deque>
    #include<map>
    #include<set>
    using namespace std;
    long long T;
    long long n,a,b,p;
    inline long long read()
    {
        long long kr=1,xs=0;
        char ls;
        ls=getchar();
        while(!isdigit(ls))
        {
            if(!(ls^45))
                kr=-1;
            ls=getchar();
        }
        while(isdigit(ls))
        {
            xs=(xs<<1)+(xs<<3)+(ls^48);
            ls=getchar();
        }
        return xs*kr;
    }
    inline long long ksc(long long x,long long y,long long mod)
    {
        long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
        return tmp<0 ? tmp+mod : tmp;
    }//O(1)快速乘 
    inline long long ksm(long long x,long long y,long long mod)
    {
        if(y==0) return 1;
        if(y==1) return x;
        if(y&1)
        {
            long long res=ksm(x,y>>1,mod);
            res=ksc(res,res,mod);
            res=ksc(res,x,mod);
            return res%mod;
        }
        else
        {
            long long res=ksm(x,y>>1,mod);
            return res=(ksc(res,res,mod));
        }
    }//快速幂 
    long long dfs(long long k)
    {
        if(k==1) return (a+b)%p; 
        if(k&1) return ksc(  ( ksm(a,(k>>1)+1,p)+ksm(b,(k>>1)+1,p) )%p , dfs(k>>1)  ,p)%p;
        return (  ksc( ( ksm(a,k>>1,p)+ksm(b,k>>1,p) )%p , dfs(k>>1) ,p)%p + ( p - ksm(ksc(a,b,p),k>>1,p) )  )%p;
    }//分治(关键) 
    int main()
    {
        freopen("guojia.in","r",stdin);
        freopen("guojia.out","w",stdout);
        T=read();
        while(T--)
        {
            n=read(),a=read(),b=read(),p=read();
            if(a==0)//特判 a 为 0 的情况 
            {
                printf("%lld
    ",ksm(b,n,p));
                continue;
            }
            printf("%lld
    ",dfs(n));//把 n 丢进递归函数二分求出答案 
        }
    return 0;
    }
  • 相关阅读:
    Ubuntu 12.10 安装 jdk-7u10-linux-x64.tar.gz(转载)
    Android-- FragmentStatePagerAdapter分页(转载)
    Windows下安装Cygwin及包管理器apt-cyg(转)
    Androidi性能优化之多线程和同步
    Androidi性能优化之高效使用内存
    综合面试---常问知识点
    路由器
    域名系统
    IP地址与子网掩码
    网络层使用的协议
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9739583.html
Copyright © 2011-2022 走看看