专栏文章
题解:AT_abc406_e [ABC406E] Popcount Sum 3
AT_abc406_e题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mip9m7th
- 此快照首次捕获于
- 2025/12/03 08:24 3 个月前
- 此快照最后确认于
- 2025/12/03 08:24 3 个月前
同机房大家都写
dfs 就我不这么写。纯计数。
我们先考虑 的 popcount 和 相等的情况。从高到低遍历 的每一位 ,假设当前是第 位(最低为第 位)。令我们枚举的数字的最高位到低 位都和 是一样的,并考虑第 位填 的情况,可以确定这样一定小于 并且不会重复。设 的第 位到第 位一共有 个 ,显然总共能产生 个不同的数字,在这些数字中考虑每个位的贡献。第 位到第 位的任意一位在这些数字中一共会在 个数字中为 。所以第 位到第 位对答案产生的总贡献为 。至于高位的部分,将 的最高位到第 位取出,为 ,则这部分的贡献为 。注意到这种方法只能统计小于 的数字,所以最后输出的答案要加 。
那么如果 的 popcount 不是 呢?如果 的 popcount 大于 ,那么就从低到高把 的 位置变成 直到 的 popcount 等于 ,然后直接按照上面的方法处理。如果 的 popcount 小于 ,也是从低到高遍历每一位,只不过是把 变成 ,并且答案不需要额外加 。
参考代码:
CPP#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define N 1000010
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define pii pair<int,int>
const ll mod = 998244353;
inline ll qpow(ll base,ll e){ll res=1;while(e){if(e&1)res=res*base%mod;base=base*base%mod;e>>=1;}return res;}
int t,k,cnt,num;ll n,ans,q;
ll f[N],g[N],p[N];
inline ll c(const int &x,const int &y){if(y > x)return 0;return f[x]*g[x-y]%mod*g[y]%mod;}
// 主函数
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin >> t;f[0] = p[0] = 1;
for(int i = 1;i < N;++i)f[i]=f[i-1]*i%mod,p[i]=p[i-1]*2%mod;g[N-1] = qpow(f[N-1],mod-2);
for(int i = N-2;i >= 0;--i)g[i]=g[i+1]*(i+1)%mod;
while(t--){cin >> n >> k;ans = q = 0;num = 0;
for(int i = 62;i >= 0;--i)if((n&(1ll<<i)))++num;
if(num >= k){for(ll pos = 1;num != k;pos <<= 1)if(n & pos){--num,n&=(~pos);}ans = n;}// 把位置卸掉
else for(ll pos = 1;num != k;pos <<= 1)if(!(n & pos)){++num,n|=pos;}// 补上
for(int i = 62;i >= 0;--i){ll pos = (1ll<<i);if(!(n&pos))continue;
ans = ans + c(i,num)*q%mod + (p[i]-1)*c(i-1,num-1)%mod;ans %= mod;--num;q += pos,q %= mod;
}cout << ans << '\n';
}
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...