大河的序列(思维题+位运算+贪心):位运算特性

105 篇文章 0 订阅

大河的序列

题目背景

“唯有龙虎相伴 最是脉脉深情”

题目来源:KingSann

题目描述

大河有一些袜子,但经常十分散乱的堆放着。

有一天龙儿忍不住了,于是将袜子放到了一个序列上(称作袜子序列)。

每个袜子都有一个 d i r t y dirty dirty值,定义袜子序列的 d i r t y dirty dirty值为 max ⁡ ( ( d i r t y l   b i t a n d   d i r t y l + 1   b i t a n d   ⋯   b i t a n d   d i r t y r ) + ( d i r t y l   b i t o r   d i r t y l + 1   b i t o r   ⋯   b i t o r   d i r t y r ) ) \max \left( (dirty_{l} \ bitand \ dirty_{l+1} \ bitand \ \cdots \ bitand \ dirty_{r}) + (dirty_{l} \ bitor \ dirty_{l+1} \ bitor \ \cdots \ bitor \ dirty_{r}) \right) max((dirtyl bitand dirtyl+1 bitand  bitand dirtyr)+(dirtyl bitor dirtyl+1 bitor  bitor dirtyr)) ,其中 d i r t y i dirty_{i} dirtyi 表示 第 i i i 只袜子 的 d i r t y dirty dirty 值, b i t a n d bitand bitand表示按位与(C++中是&), b i t o r bitor bitor表示按位或(C++中是|)。

简而言之,就是找一段连续子序列,使得所有数字的按位与加上按位或最大。

如果这个袜子序列的 d i r t y dirty dirty值达到了某个值,那么龙儿会讨厌大河的。

大河当然不希望这样了,于是她想知道这个袜子序列的 d i r t y dirty dirty值是多少。

输入格式

第一行三个整数 n , b , p n,b,p n,b,p ,分别表示数列长度和输出相关的东西

第二行有 n n n 个整数,表示这个数列的初始数值

输出格式

设答案为 x x x ,你需要输出 ( x + 233 ) b    mod    p (x+233)^{b} \,\, \text{mod} \,\,p (x+233)bmodp

样例 #1

样例输入 #1

10 1 10000000
7 9 9 4 0 0 8 8 4 7

样例输出 #1

251

提示

1 ≤ n , p ≤ 1 0 5 1 \le n, p \le 10^{5} 1n,p105

0 ≤ b , d i t r y i ≤ 1 0 7 0 \le b, ditry_{i} \le 10^{7} 0b,ditryi107

对于测试点 1 1 1 和测试点 2 2 2 的数据,保证 1 ≤ n ≤ 100 1 \le n \le 100 1n100

思路

对于题目的式子,我们定义:

s 1 = { d i  and  d i + 1  and  d i + 1 , ⋯ d j − 1  and  d j } s_1=\{d_i\ \text{and}\ d_{i+1}\ \text{and}\ d_{i+1},\cdots d_{j-1} \ \text{and}\ d_{j}\} s1={di and di+1 and di+1,dj1 and dj}

s 2 = { d i  or  d i + 1  or  d i + 1 , ⋯ d j − 1  or  d j } s_2=\{d_i\ \text{or}\ d_{i+1}\ \text{or}\ d_{i+1},\cdots d_{j-1} \ \text{or}\ d_{j}\} s2={di or di+1 or di+1,dj1 or dj}

求一个子序列,使得 s 1 + s 2 s_1+s_2 s1+s2 尽可能大。

此时假设现在存在一个子序列 s k s_k sk,那么现在要加入一个数 c c c,那么我们按位来看情况如何:

对于其中的某一位, c c c 在这一位一定存在两种情况: 0 0 0 或者位 1 1 1,我们也知道什么时候能同时满足二者最优,那么肯定是:尽可能每位要 1 1 1

而这样的一个 1 1 1 对于高位的贡献显然是大于低位的,所以我们要找的序列都要尽可能大,而任何一个 c c c,如果比原来的序列中所有数都小,那么它是无需加入的(也就是说,贡献为负)。

那么我们从任何一个数开始,把所有比他大的数加进来,那他对这个序列的贡献就是负了,那么我们就可以把它移除…依次类推,只留下了最大的数。

那么我们计算的时候,由于没有别的数,就等于将它计算了两边,此时答案就是 2 × m a x 2\times max 2×max

内容参考

  • 细节1:本题规定 0 0 = 0 0^0=0 00=0

代码

//结论 两倍

#include<iostream>
#include<algorithm>
#include<cstring>

#define int long long

using namespace std;

const int N = 1e5+10;

int w[N];
int n,b,p;
int maxv;

int qmi(int a,int b,int p){
    int res=1;
    
    while(b){
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}

signed main(){
    cin>>n>>b>>p;
    
    for(int i=1;i<=n;i++){
        cin>>w[i];
        maxv=max(w[i],maxv);
    }
    maxv*=2;
    
    if(p==1&&b==0){
        cout<<0;
    }else{
    cout<<qmi(maxv+233,b,p)<<endl;
        
    }
    
    
    
    return 0;
    
}
  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值