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;
    }
  • 相关阅读:
    今天开始用 VSU 2010
    Visual Studio 2010 模型设计工具 基本应用
    Asp.Net访问Oracle 数据库 执行SQL语句和调用存储过程
    Enterprise Library 4.1 Security Block 快速使用图文笔记
    解决“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本。”(图)
    一个Oracle存储过程示例
    Enterprise Library 4.1 Application Settings 快速使用图文笔记
    Oracle 10g for Windows 简体中文版的安装过程
    Oracle 11g for Windows 简体中文版的安装过程
    Oracle 9i 数据库 创建数据库 Net 配置 创建表 SQL查询 创建存储过程 (图)
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9739583.html
Copyright © 2011-2022 走看看