2019.7.10 校内测试题 越狱

 题目

  越狱(prison.cpp,1s,512MB)

【问题描述】:

  监狱有连续编号为 1..n 的 n 个房间,每个房间关押一个犯人。有 m 种宗教,

每个犯人可能信仰其中一种。如果相邻房间的犯人信仰的宗教相同,就可能发生
越狱。求有多少种状态可能发生越狱。

【输入文件】:

   输入两个整数 m 和 n,1≤m≤108,1≤n≤1012。

【输出文件】:

  可能越狱的状态数,模 100003 取余。

【输入输出样例】:

  prison.in
    2 3
  prison.out
    6

【数据规模】:

  6 种状态为:(000)(001)(011)(100)(110)(111)

考试得分:  10

主要算法 :  同余(快速幂)

应试策略:

  1.   首先想到DP,但是条件不允许呀,所以考虑一下的,DP不行,数论题就决定是它了
  2.        总状态数位m^n,考虑不发生越狱的情况第一个有m种,第二个就有m-1种,那么第x个(x∈[2,n])都为m-1种,那么总数为m*(m-1)^(n-1)种,那么符合条件的就是m^n-m*(m-1)^(n-1)
  3.        那么最后输出的为pow(m,n,MOD)-m*pow(m-1,n-1,MOD)%MOD+MOD,需要考虑long long

   代码

#include<stdio.h>
#include<stdlib.h>
#define LL long long 
#define FORa(i,s,e) for(LL i=s;i<=e;i++)
#define FORs(i,s,e) for(LL i=s;i>=e;i--)
#define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),stdin)?EOF:*pa++
#define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout);

using namespace std;
static char buf[100000],*pa=buf,*pb=buf;
inline LL read();

const LL MOD=100003;
LL m,n;
LL Quickpow(LL a,LL b,LL c)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=ret*a%c;
        a=a*a%c,b>>=1; 
    }
    return ret%c;
}
int main()
{
    File("prison");
    m=read(),n=read();
    LL p=Quickpow(m,n,MOD)-(Quickpow(m-1,n-1,MOD)*m%MOD);
    printf("%lld",p%MOD);
    return 0;
}
inline LL read()
{
    register LL f(1),x(0);register char c(gc);
    while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc;
    return f*x;
}

非完美算法:  

    照搬应试策略

正解:

    因为取模运算的特殊性 ,所以Quickpow(m,n,MOD)-(Quickpow(m-1,n-1,MOD)*m%MOD)可能小于0,所有要先加上MOD再取模MOD,运用同余的同加性

总结:

  1.   取模运算之间相减注意符号,运用同余的同加性

猜你喜欢

转载自www.cnblogs.com/SeanOcean/p/11164454.html