其他分享
首页 > 其他分享> > 【NOIP16提高模拟训练20】种花 flower

【NOIP16提高模拟训练20】种花 flower

作者:互联网

题目链接

种花 flower

题目描述

OI太可怕了,我决定回家种田。
我在后院里开辟了一块圆形的花圃,准备种花。种花是一种艺术,通过一定技术手法,花材的排列组合会让花变得更加的赏心悦目,这就是花艺。
当然你知道,我在种田之前是OIer,所以我不懂花艺,只会排列组合。我把花圃从圆心向外画线,分成了\(N\)块扇形,分别编号为\(1\),\(2\),\(3\).....\(N\),再从村里的商店采购了\(M\)种花。然后我大胆的决定:花圃中的每块只种\(M\)种花中的一种,相邻的两块不能种同一种花。我反应比较慢,所以我请来了机房里手速最快的强袭黯灭勋章鱼人守卫来帮我,让他试一下每种排列,看看哪种最令人赏心悦目。
有一些人,他们的美丽就在身边,也许就在自己身上,像艺术家一样,他们的眼光独到特别,可就因为他们不是艺术家,他们不被人们认可,被称之为另类。简单真实的事情总可以绽放最鲜艳的花,我欣赏这样的人的心理,当然拒绝粗鲁地对待一切。
正想着,他居然告诉我已经尝试完了。这怎么可能?这可一共有.......多少种方案来着?
众所周知的是,我的智商很低。
我想知道种花的方案一共有几种。

输入格式:

仅一行,包含两个整数,分别为\(N\)和\(M\)。

输出格式:

仅一行,包含一个整数,表示方案数。这个数可能很大,你只需要输出这个数对\(1000000007\)取模的结果。

样例输入:

3 3

样例输出:

6

数据范围:

对于20%的数据,\(0<N≤5\),\(1<M≤5\)
对于60%的数据,\(0<N≤500,000\)
对于100%的数据,\(0<N≤10^{18}\),\(1<M≤10^9\)

时间限制:

1S

空间限制:

128M

提示:

remove!!!

题解

此题的题意就是将\(m\)种点放到\(n\)个围成圈的位置里,要求相邻的点不能相同。
我们先假设\(n\)个位置是一条链,那么方案数就是\(m(m-1)^{n-1}\)。
那么如果是环的话方案数就是\(m(m-1)^{n-1}\)再减去最后一个位置和第一个位置重复的个数就行了。
考虑一下当倒数第二个位置和第一个位置相同的话,因为最后一个位置和倒数第二个位置是不同的,所以这部分的最后一个位置和第一个位置是不会相同的。
当倒数第二个位置和第一个位置不相同的话,倒数第二个位置和第一个位置的每一种不相同的情况下,最后一个位置都会存在和第一个位置一样的情况被计算在\(m(m-1)^{n-1}\)中。
所以方案数就是\(m(m-1)^{n-1}\)减去倒数第二个位置和第一个位置不相同的方案数。
如果\(F[n]\)表示有\(n\)个位置时的方案数。
那么\(F[n]=m(m-1)^{n-1}-F[n-1]\)就是方案数的递推方程了。
这里要注意一下:
\(F[1]=m\)是显而易见的。
但是当\(n=2\)时,倒数第二个位置就是第一个位置,所以\(F[2]=m(m-1)\)。
题目说\(0<N≤10^{18}\),但是递推方程的时间复杂度是\(O(n)\)的。
所以我们用等比数列求和来优化一下。
得到\(F[n]=(m-1)^n+(m-1)(-1)^n\)
接着我们再用快速幂优化后时间复杂度就变成了\(O(log_2n)\)。
上代码:

#define mod 1000000007
using namespace std;
long long n,m;
long long ksm(long long x,long long p){
    long long s=x,ans=1;
    while(p){
        if(p&1) ans*=s;
        s*=s;
        s%=mod;
        ans%=mod;
        p/=2;
    }
    return ans%mod;
}
int main(){
    scanf("%lld%lld",&n,&m);
    printf("%lld",(ksm(m-1,n)%mod+((m-1)*ksm(-1,n))%mod+mod)%mod);
    return 0;
}

标签:方案,flower,20,位置,long,种花,NOIP16,倒数,mod
来源: https://www.cnblogs.com/linjiale/p/11602032.html