1 条题解

  • 0
    @ 2025-8-24 23:13:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar _FastFT2013
    抽象之神||2024csp J:275 S:220

    搬运于2025-08-24 23:13:08,当前版本为作者最后更新于2025-04-12 20:29:47,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    本蒟蒻考试的时候也是只打了 210pts,直接场切。

    Solution:

    我们考虑将 f(x)f(x) 进行改变:

    由于 运算属于二进制运算,所以此处 xx 都用的是二进制。

    我们可以将 xx 的二进制描述成以下方式:

    (x)2=(x)_2 = 一些乱七八糟的东西 ++ 一个 00 ++ tt 个连续的 11(结尾一定是二进制第 kk 位,tt 可以为 00++ 一些乱七八糟的东西。

    这里的二进制第几位是从右往左数的,二进制串最右边才是 202^0

    我们把第一个“一些乱七八糟的东西” 写做二进制数 x1x_ 1,把第二个“一些乱七八糟的东西” 写作二进制数 x2x_2

    注意:“一些乱七八糟的东西” 是可以没有的。

    例如样例:

    33 00

    (3)2=101=(3)_2 = 101 = x1x_111++ 一个 00 ++ 一个连续的 11 ++ x2x_2(没有)。

    那么把一个二进制拆成这样有什么用呢?

    这就要提到 的计算方式了,二进制位相同得 00,不同得 11

    接下来我们将 f(x)f(x) 进行变式,通过对每部分进行讨论得出:

    原式:f(x)=x(x+2k)f(x) = x ⊕ (x + 2^k)

    对于 x2x_2 的部分,加法只会对第 kk 位以上的数字作影响,所以 x2x_2 没有动,异或值为 00

    对于(一个 00 ++ tt 个连续的 11)这部分,加法表示在第 kk 位加 11,相当于在这部分的最右边那一位加 11,则整体会变为(一个 11 ++ tt 个连续的 00),异或值为(连续的 t+1t+111)。

    对于 x1x_1 的部分,由于用一个 00 来隔开加法进位了,所以不会对当前部分产生影响,不会发生改变,异或值为 00

    所以说我们可以将 f(x)f(x) 的二进制写成这样:

    f(x)=f(x) = 以第 kk 位结尾的连续的 t+1t+111

    那这根我们算答案有什么关系呢?

    我们发现,实际上可以枚举 tt,算出二进制中有一个 00 ++ 从第 kk 为结尾连续 tt11,并且满足这个数小于等于 nn 的方案数,将方案数乘上当前贡献就可以得出当前结果。

    我们现在假设要满足以上条件,并且给出了 tt

    首先(一个 00 ++ 从第 kk 为结尾连续 tt11)可以使用公式推导出来:

    一个 00 ++ 连续 tt11 =2t1= 2^t - 1

    上述条件加上以第 kk 结尾 =(2t1)×2k=(2^t - 1) \times 2^k

    然后我们要求出满足条件的最大的数,

    这个不能使用公式进行推导,我们可以从高位枚举到低位,每次查看能不能把这个位变为 11 并且满足条件,若能,就把这个位变为 11

    提示:在第 kk 位到第 k+tk+t 位不能改,应为这是(一个 00 ++ 从第 kk 为结尾连续 tt11)。

    设这个满足条件的最大数为 pp

    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);
    	}
    }
    

    现在我们求出来了,那怎么做呢?

    我们考虑 ppx1x_1x2x_2,将 aabb 设为这两个值(此处只是为了简便)。

    公式推导 aabb

    aapp 的二进制去掉后 t+k+1t + k + 1 位的值,

    a=p2t+k+1a = \lfloor \frac{p}{2^{t+k+1}} \rfloor

    bbpp 的二进制后 k1k-1 位,

    b=pmod(k1)b = p \bmod (k-1)

    ll a=p>>(i+k+t),b=p%(1ll<<k);
    

    我们将满足条件的数的情况分为两种:

    第一种:满足条件的数的 x1<ax_1 < a,则满足条件的数的 x2x_2 可以为任何前 k1k-1 位的二进制数(想不出来的可以画图理解)。

    则方案数为:

    x1<ax_1 < a)的方案 =a+11=a= a + 1 - 1 = a(相当于减去了 x1=ax_1 = a 的情况,增加了 x1=0x_1 = 0 的情况)。

    x2x_2 可以为任何 k1k-1 位的二进制数)的方案 =2k= 2^k(相当于每一位有 22 种情况,从共有 kk 位(00 这一位要记录进去))。

    第一种的总方案 ==((x1<ax_1 < a)的方案)×\times((x2x_2 可以为任何 k1k-1 位的二进制数)的方案)=a×2k= a \times 2^k 设其为 q1q_1

    ll q1=a<<k;
    

    第二种:满足条件的数的 x1=ax_1 = a,则满足条件的数的 x2x_2 可以为任何 b\le b 位的二进制数(想不出来的可以画图理解)。

    则方案数为:

    x1=ax_1 = a) 的方案 =1= 1

    x2x_2 可以为任何 b\le b 位的二进制数)的方案 =b+1= b + 1(加的 11x2=0x_2 = 0 的情况)。

    第二种的总方案 ==((x1=ax_1 = a)的方案)×\times((x2x_2 可以为任何 b\le b 位的二进制数)的方案)=1×(b+1)= 1 \times (b + 1) 设其为 q2q_2

    ll q2=b+1;
    

    所以总的方案数为 q1+q2q_1 + q_2

    答案为之前推出来的(以第 kk 位结尾的连续的 t+1t+111=2t+11= 2^{t+1} - 1

    当前总答案为 (q1+q2)×(2t+11)(q_1 + q_2) \times (2^{t+1} - 1)

    tt 这个数只需要枚举就好了。

    单次时间复杂度 O(log2n)O(\log^2 n)

    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

    【MX-X11-T1】「蓬莱人形 Round 1」仅此而已,就已经足够了

    信息

    ID
    11229
    时间
    2000ms
    内存
    512MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者