11.6 T1 谜团 (mituan)

*PS: 没开long long被卡掉45分,果然出题人的话都不可信QAQ。。(学傻了)


与zqsz的互测题 T1 原题 POJ 1845


【题目描述】

谜团,是夜魇军团一名强大的战士。他来自远古,是一种不可思议的重力生命体,是来自原始黑暗的扭曲声音,在宇宙中的第一丝光线诞生前就存在的深渊化身。他能动用深渊之力将生物的身体污染,使之转化为自身的碎片“虚灵”。
“虚灵”为谜团所控,拥有一定的战斗力。更为恐怖的是,新产生的“虚灵”的 第一次攻击将吸收被攻击者内心的黑暗,从而分裂成若干个“虚灵”,之后的攻击将无法产生“虚灵”,新产生的“虚灵”第一次攻击仍可产生“虚灵”。 作为天辉军团智囊的你,需要知道某一时刻谜团最多可以产生多少“虚灵”,从而据
此来进行决策。具体的,谜团在 第一秒会转化一个单位,使之变成一个“虚灵”,由于能量消耗过大,谜团在之后的时间内将不再转化单位,使之变成“虚灵”。新产生的“虚灵”会在下一秒攻击一次,从而分裂出 m 个“虚灵”,原有的“虚灵”仍然存在,并且将不再产生虚灵。但新产生的“虚灵”可在下一秒攻击一次并分裂,之后也将不再产生“虚灵”(具体见样例解释)。给定时间 t 和分裂数 m,请你告诉天辉军团的战士们,在 t 秒后,谜团拥有多少个“虚灵”。
答案可能很大,要求你模一个数 k(不保证 k 是质数)。

【输入格式】

第一行:三个整数 m,t,k,意义见题目描述

【输出格式】

第一行:t 秒后谜团拥有的能量体个数

【样例输入 1】

3 3 1000

【样例输出 1】

13

【样例输入 2】

3 5 1000

【样例输出 2】

121

【样例 1 解释】

m = 3, t = 5 时:
第一秒:谜团制造 1 个“虚灵”
第二秒:1 个“虚灵”分裂出 3 个“虚灵”,此时共有 4 个“虚灵”
第三秒:第 1 秒制造的 1 个“虚灵”将不能分裂,第 2 秒制造的 3 个“虚灵”,
每个“虚灵”分裂成 3 个“虚灵”,新分裂出的“虚灵”有 9 个,此时共有 13
个“虚灵”。
最终,总共有 13 个“虚灵”

【数据规模与约定】

保证 k,m,t 及答案在 int 范围内(注意只有答案!!!)

这里写图片描述

原题意是求A^B的约数个数,因为出题人很良心(原话),所以就改为求首项为1,公比为m的等比数列的前n项和。

部分分


1~8 暴力枚举


9~12 特殊性质:模数k是质数,因为等比数列的前n项和为 q^n-1/(q-1),除法的取模需要用到逆元,可以用费马小定理做。
a^(p-1) ≡ 1(mod p) —> a^(p-2) ≡ 1/a (mod p)

ll ans=(multiply(T,M)-1)%K*multiply(K-2,M-1)%K%K;
printf("%lld",ans);

13~16 (原话)特殊性质 k不是质数,但k与m互质,用扩展欧几里得求逆元。

但是,我用的扩展欧几里得是要求m-1在%k意义下的逆元啊喂!! 没有给部分分QAQ。

直接打exgcd可以的50分,前提是你开了long long ,但是我并没有开qwqqqq(让我自己一个人静一会)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

long long M,T,K,ans;

long long multiply(long long n,long long a)
{
    long long sum=1,x=a;
    while(n)
    {
        if(n&1) sum=sum%K*x%K%K;
        x=x%K*x%K%K;
        n>>=1;
    }
    return sum%K;
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    long long d=exgcd(b,a%b,y,x);
    y=y-a/b*x;
    return d;
}
int main()
{
    freopen("mituan.in","r",stdin);
    freopen("mituan.out","w",stdout);
    scanf("%lld%lld%lld",&M,&T,&K);
    {
        long long x,y;
        long long d=exgcd(M-1,K,x,y);
        x%=K;
        while(x<0) x+=K/d;
        ans=(multiply(T,M)-1)%K*x%K%K;
        if(ans<0) ans+=K;
        printf("%lld",ans);
    }
    return 0;
}

17~20 没有特殊性质 qwq


1~20

正解 1 公式求逆元

安利一个之前看到的博客(为什么我当时没有好好看qwq)

http://blog.csdn.net/acdreamers/article/details/8220787

因为费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求a与m互素。

但是我们有一个公式,若 b|a , 则ans即为(a/b)mod m 的答案:

这里写图片描述

证明:

(a/b)mod m = ans ;

a/b = ans + k * m ;

a = ans * b + k * m * b ;

a mod ( bm ) = ans * b ;

a mod ( bm ) / b = ans ;

得证。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define ull unsigned long long 

ull M,T,K;

ull multiply(ull n,ull a)
{
    ull sum=1,x=a;
    while(n)
    {
        if(n&1) sum=sum%K*x%K%K;
        x=x%K*x%K%K;
        n>>=1;
    }
    return sum%K;
}
int main()
{
    freopen("mituan.in","r",stdin);
    freopen("mituan.out","w",stdout);
    scanf("%lld%lld%lld",&M,&T,&K);
    K=K*(M-1);
    ull ans=(multiply(T,M)-1)/(M-1);
    printf("%lld",ans);
    return 0;
}

正解 2 二分+递归

数学课上的求等比数列的前n项和有一个公式,emmm,公式有很多的变形,其中有一个变形为

这里写图片描述

若另 n 和 m 都等于 t/2 ,可知

这里写图片描述

所以我们要求St,只需要每次二分的递归下去,在递归的过程中取模就可以了。

另外注意递归的时候要分t为奇数和偶数的情况,因为计算机里的/是会自动下取整的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

ll M,T,K;

ll pow(ll a,ll n)
{
    ll sum=1,x=a;
    while(n)
    {
        if(n&1) sum=sum%K*x%K%K;
        x=x%K*x%K%K;
        n>>=1;
    }
    return sum;
}

ll sum(ll q,ll t) // q^0+q^1+q^2+...+q^t --> S(t+1)
{
    if(t==0) return 1;
    if(t%2==0) return (sum(q,t/2-1)%K*(1+pow(q,t/2))%K%K+pow(q,t)%K)%K; 
    //t 为偶数,说明S(t+1)没法直接通过S((t+1)/2)求得,就去求St,最后加上一个q^t次方 
    else return (sum(q,t/2)%K*(1+pow(q,t/2+1))%K)%K; 
    //t 为奇数,说明S(t+1)可以直接用(S(t+1)/2)求得,又S((t+1)/2)即为sum(q,t/2)(t/2下取整),可以直接求 (t/2+1即为(t+1)/2)  
}
int main()
{
    freopen("mituan.in","r",stdin);
    freopen("mituan.out","w",stdout);
    scanf("%d%d%d",&M,&T,&K);
    printf("%lld",sum(M,T-1));
    return 0;
}

PS:刚刚把这篇博客搬到了博客园里,果然背景什么的都好漂亮(捂脸)。。虽然写的时候很麻烦。。。但是好看啊!!! 链接:http://www.cnblogs.com/maple-kingdom/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章