2024杭电ACM-个人PK赛(1):1004 合法数对

2024杭电ACM-个人PK赛(1)

1004 合法数对

Time Limit (Java / Others)
2000 / 1000 MS
Memory Limit (Java / Others)
327680 / 327680 K
Ratio (Accepted / Submitted)
12.06% (219/1816)

Problem Description

数对 ( x , y ) (x,y) (x,y) 是好的,当且仅当 x ⊕ y = x ∣ y x⊕y=x∣y xy=xy,其中 ⊕ ⊕ 表示异或操作, ∣ ∣ 表示或运算。
给定正整数 N N N,请你求解有多少个好的数对 ( x , y ) (x,y) (x,y),满足 x , y ∈ [ 0 , N ] x,y∈[0,N] x,y[0,N]​。
因为出题人小 M M M 比较仁慈,所以 N N N 将以二进制的形式给出。
答案对 998244353 ​ 998244353​ 998244353​ 取模。

Input

输入共 1 1 1 行,包含一个正整数 N N N,通过二进制的形式给出。

评测数据规模:
对于所有测评数据, 1 ≤ N < 2 1234567 1≤N<2^{1234567} 1N<21234567

Output

输出共 1 1 1 行,输出 1 1 1 个整数,表示最终答案,答案对 998244353 998244353 998244353 取模。

Sample Input

111 111 111

Sample Output

27 27 27

思路分析

认识“异或”和“或”

  • 异或 ( ⊕ ⊕ )
    0 ⊕ 0 = 0 0⊕0=0 00=0
    0 ⊕ 1 = 1 0⊕1=1 01=1
    1 ⊕ 0 = 1 1⊕0=1 10=1
    1 ⊕ 1 = 0 1⊕1=0 11=0
  • 或 ( ∣ | )
    0 ∣ 0 = 0 0|0=0 0∣0=0
    0 ∣ 1 = 1 0|1=1 0∣1=1
    1 ∣ 0 = 1 1|0=1 1∣0=1
    1 ∣ 1 = 1 1|1=1 1∣1=1

分析与计算

易知当 ( x , y ) = ( 1 , 1 ) (x,y)=(1,1) (x,y)=(1,1) 时不满足题意,由此可以延伸至 N N N 的每一位。

通过计算得知,输入每增加 1 1 1,输出的变化量 D D D 0 0 0 的个数 m m m 有关。
① 只有在与 0 0 0 进行异或以及运算的时候才会相等。
② 进行运算的位可以取值 0 0 0 1 1 1 两种,所以 d = 2 m d=2^m d=2m
( x , y ) (x,y) (x,y) ( y , x ) (y,x) (y,x) 视为不同的数对,所以 D = d × 2 = 2 m + 1 D=d\times2=2^{m+1} D=d×2=2m+1

然后没什么思路了,打个表先,看看能不能找到一点规律。

InputN.count(0)DOutputFunct
0 0 0 1 1 1 1 1 1 1 1 1
1 1 1 0 0 0 2 2 2 3 3 3 1 × 3 1\times3 1×3
10 10 10 1 1 1 4 4 4 7 7 7
11 11 11 0 0 0 2 2 2 9 9 9 3 × 3 3\times3 3×3
100 100 100 2 2 2 8 8 8 17 17 17
101 101 101 1 1 1 4 4 4 21 21 21 7 × 3 7\times3 7×3
110 110 110 1 1 1 4 4 4 25 25 25
111 111 111 0 0 0 2 2 2 27 27 27 9 × 3 9\times3 9×3
1000 1000 1000 3 3 3 16 16 16 43 43 43
1001 1001 1001 2 2 2 8 8 8 51 51 51 17 × 3 17\times3 17×3
1010 1010 1010 2 2 2 8 8 8 59 59 59
1011 1011 1011 1 1 1 4 4 4 63 63 63 21 × 3 21\times3 21×3
1100 1100 1100 2 2 2 8 8 8 71 71 71
1101 1101 1101 1 1 1 4 4 4 75 75 75 25 × 3 25\times3 25×3
1110 1110 1110 1 1 1 4 4 4 79 79 79
1111 1111 1111 0 0 0 2 2 2 81 81 81 27 × 3 27\times3 27×3
x x x 0 xxx0 xxx0 m m m 2 m + 1 2^{m+1} 2m+1 f ( x x x ) × 3 − 2 m f(xxx)\times3-2^m f(xxx)×32m
x x x 1 xxx1 xxx1 m − 1 m-1 m1 2 m 2^m 2m f ( x x x ) × 3 f(xxx)\times3 f(xxx)×3 f ( x x x ) × 3 f(xxx)\times3 f(xxx)×3

不难看出,当末位为 1 1 1 时,可由 N N N 右移一位的结果乘 3 3 3 得到答案。
当末位为 0 0 0 时,可由 N N N 右移一位的结果乘 3 3 3 再减去 d = 2 m d=2^m d=2m 得到答案。
这里采用减法是因为从 x x x 1 xxx1 xxx1 x x x 0 xxx0 xxx0 不涉及进位退位,便于计算。

便可以从末位向前遍历,得到的这个计算过程将是倒序的。
为了避免递归的写法爆栈,手动把计算过程压入堆栈(后进先出)达到反序的目的。
本代码使用了 STL 中的 vector 来模拟堆栈。

代码实现

#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll q_pow(ll a,ll b) { ll ans = 1; while(b) { if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans % mod; }
vector<ll> v;
int main(){
    ll b = 0; string ss; cin >> ss;
    for(auto p : ss) if(p == '0') b++;          //记录0的个数
    while(!ss.empty()){
        if(*ss.rbegin()=='1') v.push_back(0);   //不需要减,用0占位
        else v.push_back(b--);                  //存入即时0的个数
        ss.pop_back();
    }ll ans=1;
    while(!v.empty()){
        ans *= 3;
        if(*v.rbegin()) ans -= q_pow(2, *v.rbegin()); 
        ans = (ans+mod)%mod;                    //保证ans>0
        v.pop_back();
    }cout << ans << "\n";
}

。。。我写复杂了,去看这篇吧,写得挺好的【2024杭电ACM-个人PK赛(1) 1004合法数对 - HDU7415】

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
ACM-ICPC(国际大学生程序设计竞)是一项面向大学生的计算机编程竞,涉及算法和数据结构等领域。在比中,选手需要解决一系列编程问题,使用合适的算法和数据结构来实现正确和高效的解决方案。 对于整理ACM-ICPC模板,以下是一些建议: 1. 了解比要求:首先,你需要了解ACM-ICPC比的具体要求和规则。这包括了解比所涉及的算法和数据结构,以及题目的类型和难度等。 2. 收集资料:收集与ACM-ICPC相关的资料,包括经典算法和数据结构的实现代码、常见问题的解题思路等。可以参考教材、博客、论文等资源。 3. 整理模板:将收集到的资料整理成模板。可以按照算法和数据结构的分类进行整理,例如排序算法、图算法、字符串算法等。对每个模板,添加必要的注释和示例代码,以便理解和使用。 4. 测试代码:对每个模板编写测试代码,确保它们的正确性和可靠性。可以使用已知的测试用例或自行设计测试用例。 5. 更新与扩充:定期更新和扩充模板,以适应ACM-ICPC比中新出现的算法和数据结构。同时,根据自己的经验和理解,对模板进行优化和改进。 6. 练习和复习:在比之前,利用整理好的模板进行练习和复习。尝试解决一些经典问题,使用模板中的算法和数据结构进行实现,并进行优化。 希望这些建议对你整理ACM-ICPC模板有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jord8061

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

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

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

打赏作者

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

抵扣说明:

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

余额充值