快速幂取模练习

B

Description

美旸旸今天碰到一道简单题。
给你一个数n,代表有1到n这n个数。要你把它们排成一个漂亮的排列。
漂亮的排列是满足下面条件之一的排列:
1. a1...ai递增,ai...an递减
2. a1...ai递减,ai...an递增
漂亮的排列的个数可能非常大,要求你输出个数%p
美旸旸看完题目后不屑一笑,随手敲完代码就AC了。

Input

有多组输入,少于1000组。
每组测试数据有两个数:n,p。(1<= n,p <=1e18)

Output

对于每组测试数据,输出一行答案,个数%p。

Sample Input

2 233
3 5

Sample Output

2
1

HINT

 

找规律啦,ai要么最大要么最小,把ai位置定好就可以讨论啦

当ai为最大  c(1,n-1)+c(2,n-1)+......+c(n-1,n-1)=2^(n-1)

同理可得ai为最小 2^(n-1)

然后i=1和i=n被重复计算啦

所以得-2

个数为2^n-2

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod;
ll mul(ll a,ll b) // a*b 快乘
{
    ll ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
ll pow(ll a,ll b) // a^b 快速幂
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
    }
    return ans;
}
int main()
{
    ll n;
    while(~scanf("%lld %lld",&n,&mod))
    {
        if(n ==1)
            printf("%lld\n",n%mod); // 特判直接输出1就完事
        else
            printf("%lld\n",((pow(ll(2),n)-2+mod))%mod);
    }
    return 0;
}

D

Description

Averyboy最近迷上了中国环游戏,但是他绞尽脑汁也不会把环拆下来,于是他请教聪明的你帮他解决问题。
首先,杆子上有n个环,第一个环可以挂上或拆下。如果你想挂上或拆下第n个环,那必须满足以下条件:
1. 第n-1个环是挂上的
2. 前n-2个环是拆下的
问题是把n个环全部拆下需要的最少操作次数。

Input

输入文件每行一个数n,n <= 1e9,最后一行是数字0。

Output

每行输出一个数X,代表最少操作次数。X可能很大,输出X%201807

Sample Input

1
4
0

Sample Output

1
10

HINT

我们继续找规律啦

类似汉诺塔。将环分为三个部分

假设F(n)为对n个环拆下(挂上)所需的操作次数

依题意得F(n)=F(n-2)【拆下】+1+F(n-2)【挂上】+F(n-1)【拆下】

然后造矩阵了

[F(n),F(n-1),1]=A*B^(n-2)

矩阵A为Mat tmp

矩阵B为Mat b

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=3;
LL mod=201807;
struct Mat
{
    LL mat[N][N];
};
Mat mul(Mat a,Mat b)//矩阵相乘模板
{
    Mat ans;
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            ans.mat[i][j]=0;
            for(int k=0; k<N; k++)
            {
                ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
                ans.mat[i][j]%=mod;
            }
        }
    }
    return ans;
}
Mat quickPow(Mat a,int n)//快速幂取模
{
    Mat ans=   //单位矩阵
    {
        1,0,0,
        0,1,0,
        0,0,1

    };
    while(n)
    {
        if(n&1)
            ans=mul(ans,a);
        n>>=1;
        a=mul(a,a);
    }
    return ans;
}
int main()
{
    int n;
    Mat ans;
    while(scanf("%d",&n)&&n)
    {
        Mat b=
    {
        1,1,0,
        2,0,0,
        1,0,1
    };
        Mat tmp=
    {

        2,1,1,
        0,0,0,
        0,0,0
    };
       if(n == 1)   printf("1\n");
        else if(n == 2) printf("2\n");
            else {
                ans=quickPow(b,n-2);
                ans=mul(tmp,ans);
                cout<<ans.mat[0][0]<<endl;
                 }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41394420/article/details/81070450