HDU 5187 zhx's contest

题意:给出整数n,求1...n的排列中有那些数是13542或53124,即先上升后下降或先下降后上升,可以完全上升或下降。答案和p取模。

 

解法:找呀找呀找规律。从样例可以直接猜到规律就是2 ^ n - 2,然后我大概推理了一下。

当n等于3时,可以发现所有的排列都符合这一特点。

123, 132, 213, 231, 312, 321。

当新加入一个数字4时,对于完全上升或下降的排列有三个位置可以添加,3的两端和1的一端,例如123添加4后变成4123, 1243, 1234。对于先上升后下降的排列有两个位置可以添加,3的两端,例如132添加4后变成1432, 1342。对于先下降后上升的排列同样有两个位置可以添加,排列的两端,例如213添加4后变成4213, 2134。

所以对于n等于3时的答案a3来说,a4 = 2 * a3 + 2。得出数列ai = 2 * ai-1 + 2,求其通项公式得a1 = 1, an = 2 ^ n - 2。

由于n很大,使用快速幂计算。愉快的过了一判……二判TLE了,后来一看才知道因为p太大了还要用快速乘法这么个东西……原理和快速幂类似……orz

 

代码:

妈妈问我为什么跪着写代码系列

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
LL n, p;
LL MUL(LL x, LL n)//快速乘法
{
    LL ret = 0;
    LL base = x;
    while(n)
    {
        if(n & 1)
            ret = (ret + base) % p;
        base = (base + base) % p;
        n >>= 1;
    }
    return ret;
}
LL POW(LL x, LL n)//快速幂
{
    LL base = x;
    LL ret = 1;
    while(n)
    {
        if(n & 1)
            ret = MUL(ret, base) % p;
        base = MUL(base, base) % p;
        n >>= 1;
    }
    return ret;
}
int main()
{
    while(~scanf("%lld%lld", &n, &p))
    {
        if(n == 1)
            printf("%lld\n", ((LL)1 % p));
        else
        {
            LL tmp = POW(2, n);
            printf("%lld\n", (tmp - 2 + p) % p);
        }
    }
    return 0;
}

  

posted @ 2015-03-22 16:46  露儿大人  阅读(158)  评论(0)    收藏  举报