Codeforces Round #307 (Div. 2)D

30 篇文章 0 订阅
8 篇文章 0 订阅

D. GukiZ and Binary Operations
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
We all know that GukiZ often plays with arrays.

Now he is thinking about this problem: how many arrays a, of length n, with non-negative elements strictly less then 2l meet the following condition: ? Here operation means bitwise AND (in Pascal it is equivalent to and, in C/C++/Java/Python it is equivalent to &), operation means bitwise OR (in Pascal it is equivalent to , in C/C++/Java/Python it is equivalent to |).

Because the answer can be quite large, calculate it modulo m. This time GukiZ hasn’t come up with solution, and needs you to help him!

Input
First and the only line of input contains four integers n, k, l, m (2 ≤ n ≤ 1018, 0 ≤ k ≤ 1018, 0 ≤ l ≤ 64, 1 ≤ m ≤ 109 + 7).

Output
In the single line print the number of arrays satisfying the condition above modulo m.

Examples
input
2 1 2 10
output
3
input
2 1 1 3
output
1
input
3 3 2 10
output
9
Note
In the first sample, satisfying arrays are {1, 1}, {3, 1}, {1, 3}.

In the second sample, only satisfying array is {1, 1}.

In the third sample, satisfying arrays are {0, 3, 3}, {1, 3, 2}, {1, 3, 3}, {2, 3, 1}, {2, 3, 3}, {3, 3, 0}, {3, 3, 1}, {3, 3, 2}, {3, 3, 3}.

这个题其实思路是这样的
把那个k二进制分开
因为每一位之间互相不影响所以只要一位一位的判断就可以了
还要注意的一个东西是取余…
不知道怎么回事取到了负的??
不过无所谓…
以后取余数一定要注意最后变成正的

然后因为是一位一位的判断
一位是1的条件其实只要连续两个是1就可以的

然后求的时候就是有点技巧
一开始可以看做是一个dp
二维的 求得是这意味是0的情况
这个dp第一维是求第几位第二维是求这个是1还是0
打个表转移就可以
发现其实是个斐波那契
然后理所当然的矩阵快速幂

处理一些特殊情况就可以
比如l的位数其实比k多?、
比如l其实比k小?

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long n, k, m, l;
struct juzhen
{
    long long zz[2][2];
};
juzhen cheng(juzhen p, juzhen q)
{
    juzhen qq = { { { 0,0 },{ 0,0 } } };
    for (int a = 0;a < 2;a++)
    {
        for (int b = 0;b < 2;b++)
        {
            for (int c = 0;c < 2;c++)
            {
                qq.zz[a][b] += (p.zz[a][c] * q.zz[c][b]) % m;
            }
        }
    }
    return qq;
}
juzhen ksm(juzhen di, long long zhishu)
{
    juzhen fanhui;
    for (int a = 0;a < 2;a++)
    {
        for (int b = 0;b < 2;b++)
        {
            if (a == b)fanhui.zz[a][b] = 1;
            else fanhui.zz[a][b] = 0;
        }
    }
    while (zhishu)
    {
        if (zhishu & 1)fanhui = cheng(fanhui, di);
        zhishu >>= 1;
        di = cheng(di, di);
    }
    return fanhui;
}
long long kksm(long long di, long long zhishu)
{
    long long fanhui = 1;
    while (zhishu)
    {
        if (zhishu & 1)fanhui *= di;
        fanhui %= m;
        zhishu >>= 1;
        di *= di;
        di %= m;
    }
    return fanhui%m;
}
int main()
{
    cin >> n >> k >> l >> m;
    if (pow(2,l) <= k)
    {
        cout << 0;
        return 0;
    }
    juzhen kp;
    kp.zz[0][0] = kp.zz[0][1] = kp.zz[1][0] = 1;
    kp.zz[1][1] = 0;
    long long ling, yi;
    kp = ksm(kp, n);
    ling = (kp.zz[0][0] + kp.zz[0][1]) % m;
    long long quan = kksm(2, n);
    yi = quan - ling;
    long long jg = 1;
    while (k)
    {
        if (k & 1)jg *= yi;
        else jg *= ling;
        k >>= 1;
        jg %= m;
        l--;
    }
    while (l >= 1)
    {
        jg *= ling;
        jg %= m;
        l--;
    }
    jg += m;
    jg %= m;
    cout << jg;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值