CF1816F Xor Counting - dp - 分治 -

题目链接:https://codeforces.com/contest/1816/problem/F

题解:
一道有趣的题。

  • 首先发现 m=1m3 时结论是平凡的。m=1 时结论显然,下面讨论一下 m3 时:
    首先可以构造 [x,(nx)/2,(nx)/2,],其中 xn 同奇偶,显然此时异或值可以取到 1n 的所有和 n 奇偶性相同的值。另一方面,一个重要观察是 a1an 的奇偶性和 a1++an 相同,因此异或值至多取到所有和 n 奇偶性相同的值。因此这块可以 O(1) 求出。
  • 下面我们讨论一下 m=2 的情况。
    fn 表示 a1+a2=n 时的答案,考虑分治:
    如果 n 为奇数,那么 a1,a2 一奇一偶,不失一般性设 a1,a2 分别为奇数 偶数,如果令 b1=(a11)/2,b2=a2/2,那么 b1+b2=(n1)/2,b1b2=2×(a1a2)+1,因此我们还需要记一个 gn 表示有多少种不同的异或值(因为这个 +1 是对于所有不同的异或值都要算的),gn 此时的转移也很简单。综上我们有 n 为奇数时 fn=2×fn/21+gn 以及 gn=g(n1)/2
    如果 n 为偶数,那么 a1,a2 要么都是奇数,要么都是偶数,还是考虑 /2 分治,此时由于 n 奇数,所以没有 +1 的项,因此和上一种情况完全相同的推导我们有 fn=2×(fn/2+fn/21) 以及 gn=gn/2+gn/21

直接递推实现即可,复杂度 O(logn)
代码:

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, mod = 998244353;

map<ll,ll>f,g;
void solve(ll n){
	if(n == 0){
		f[n] = 0, g[n] = 1;
		return ;
	}
	if(f.count(n))return ;
	if(n%2 == 1){
		solve(n/2);
		(f[n] = 2ll*f[n/2]%mod + g[n/2])%=mod;
		g[n] = g[n/2];
	}else{
		solve(n/2);solve(n/2-1);
		f[n] = 2ll * (f[n/2] + f[n/2-1]) % mod;
		g[n] = (g[n/2] + g[n/2-1]) % mod;
	}
}

signed main(){
	int te;scanf("%d",&te);
	while(te --){
		f.clear(), g.clear();
		ll n,m;cin >> n >> m;
		if(m == 1){
			cout << n%mod << '\n';
		}else if(m >= 3){
			if(n%2 == 1)cout << (n+1)/2%mod*((n+1)/2%mod)%mod << '\n';
			else cout << (1+n/2%mod)*(n/2%mod) % mod << '\n';
		}else{
			solve(n);
			cout << f[n] << '\n';
		}
	}

	return 0;
}
posted @   SkyRainWind  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示