1 条题解
-
0
自动搬运
来自洛谷,原作者为

_FastFT2013
抽象之神||2024csp J:275 S:220搬运于
2025-08-24 23:13:08,当前版本为作者最后更新于2025-04-12 20:29:47,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
本蒟蒻考试的时候也是只打了 210pts,直接场切。
Solution:
我们考虑将 进行改变:
由于 运算属于二进制运算,所以此处 都用的是二进制。
我们可以将 的二进制描述成以下方式:
一些乱七八糟的东西 一个 个连续的 (结尾一定是二进制第 位, 可以为 ) 一些乱七八糟的东西。
这里的二进制第几位是从右往左数的,二进制串最右边才是 。
我们把第一个“一些乱七八糟的东西” 写做二进制数 ,把第二个“一些乱七八糟的东西” 写作二进制数 。
注意:“一些乱七八糟的东西” 是可以没有的。
例如样例:
() 一个 一个连续的 (没有)。
那么把一个二进制拆成这样有什么用呢?
这就要提到 的计算方式了,二进制位相同得 ,不同得 。
接下来我们将 进行变式,通过对每部分进行讨论得出:
原式:。
对于 的部分,加法只会对第 位以上的数字作影响,所以 没有动,异或值为 。
对于(一个 个连续的 )这部分,加法表示在第 位加 ,相当于在这部分的最右边那一位加 ,则整体会变为(一个 个连续的 ),异或值为(连续的 个 )。
对于 的部分,由于用一个 来隔开加法进位了,所以不会对当前部分产生影响,不会发生改变,异或值为 。
所以说我们可以将 的二进制写成这样:
以第 位结尾的连续的 个 。
那这根我们算答案有什么关系呢?
我们发现,实际上可以枚举 ,算出二进制中有一个 从第 为结尾连续 个 ,并且满足这个数小于等于 的方案数,将方案数乘上当前贡献就可以得出当前结果。
我们现在假设要满足以上条件,并且给出了 。
首先(一个 从第 为结尾连续 个 )可以使用公式推导出来:
一个 连续 个 。
上述条件加上以第 结尾 。
然后我们要求出满足条件的最大的数,
这个不能使用公式进行推导,我们可以从高位枚举到低位,每次查看能不能把这个位变为 并且满足条件,若能,就把这个位变为 。
提示:在第 位到第 位不能改,应为这是(一个 从第 为结尾连续 个 )。
设这个满足条件的最大数为 。
ll p=((1ll<<t)-1)<<k; if(p>n)continue;//此处判断有没有方案 for(int j=30;j>=0;j--){//高位枚举到低位 if(j>=k&&j<=k+t)continue; if(p+(1ll<<j)<=n){ p+=(1ll<<j); } }现在我们求出来了,那怎么做呢?
我们考虑 的 和 ,将 和 设为这两个值(此处只是为了简便)。
公式推导 和 :
为 的二进制去掉后 位的值,
及 。
为 的二进制后 位,
及 。
ll a=p>>(i+k+t),b=p%(1ll<<k);我们将满足条件的数的情况分为两种:
第一种:满足条件的数的 ,则满足条件的数的 可以为任何前 位的二进制数(想不出来的可以画图理解)。
则方案数为:
()的方案 (相当于减去了 的情况,增加了 的情况)。
( 可以为任何 位的二进制数)的方案 (相当于每一位有 种情况,从共有 位( 这一位要记录进去))。
第一种的总方案 (()的方案)(( 可以为任何 位的二进制数)的方案) 设其为 。
ll q1=a<<k;第二种:满足条件的数的 ,则满足条件的数的 可以为任何 位的二进制数(想不出来的可以画图理解)。
则方案数为:
() 的方案 。
( 可以为任何 位的二进制数)的方案 (加的 是 的情况)。
第二种的总方案 (()的方案)(( 可以为任何 位的二进制数)的方案) 设其为 。
ll q2=b+1;所以总的方案数为 。
答案为之前推出来的(以第 位结尾的连续的 个 )。
当前总答案为 。
这个数只需要枚举就好了。
单次时间复杂度 。
Code:
#include<bits/stdc++.h> #define ll long long using namespace std; void solve(){ ll n,k; cin>>n>>k; ll sum=0; for(int i=0;i<=30;i++){//这里的i就是t ll p=((1ll<<i)-1)<<k; if(p>n)continue; for(int j=30;j>=0;j--){ if(j>=k&&j<=k+i)continue; if(p+(1ll<<j)<=n){ p+=(1ll<<j); } } ll a=p>>(i+k+1),b=p%(1ll<<k); ll q1=a<<k; ll q2=b+1; sum+=(q1+q2)*(((1ll<<(i+1))-1)<<k); } cout<<sum<<"\n"; } int main(){ int t; cin>>t; while(t--)solve(); return 0; }
- 1
信息
- ID
- 11229
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者