???--???二进制变换

题意 :

定义两种变换

1 : i = i - 1

2 : i = i - lowbit (i)

定义函数Calc(i,j)为二进制意义下 i 变换到 j 的最小步数。

给你一个二进制整数 n,要求 sigma {(i = 1 -> n) sigma {(j = 0 -> i - 1) Calc (i,j)}}

数据范围 :

令n的长度为len

len <= 1000000

-----------------------------------------------此后一千里-----------------------------------------------------

首先有一个很显然的性质,就是如果 i 用了2操作之后还比 j 大的话,那么一定用2操作,因为减去lowbit不比减去1差

我们设 f(n) = sigma {(i = 0 -> n-1) Calc (n,i)},

我们考虑将n按位处理掉,设t(n)为n只保留的二进制最高位的数,我们发现对于Calc (n,i) 如果 t(n) == t(i) 那么答案显然是 Calc (n-t(n),i-t(i))

而如果 t(n)!=t(i) 那么我们无论如何要把 n 变换到 i 都必须把 n 变换到 t(n) ,而显然 t(n)!=t(i) 的 i 有 t(i) 个.

所以我们便可以将 f(n) 拆分掉得到 f(n) = t(n) * (BitCount(n) - 1) + f( n - t(n)),我们可以一直拆下去,也就是说我们只用算2的整次幂的 f 就可以了。

假设我们已经求出2的0-3次幂,要求 f (10000) , 因为除了变换到0,10000变换到任何数都要先变换到1111,所以我们可以得到下式 :

f(10000) = f(1111) + 1111 - 4 + 1 减4加1意思是去掉1111变到0的代价,加上10000变到0的代价

我们将f(1111) 再展开即可得到 f 关于2的整次幂的递推式,前缀和优化一下可以O(n)预处理

设 g(n) = sigma{(i = 1 -> n) f(i)},g(n)求的实际上就是答案

我们还是考虑去按位处理掉

g(n) =sigma{(i = 1 -> t(n)-1) f(i)} + sigma{(i = t(n) -> n) f(i)}

  = g(t(n) - 1) + sigma{(i = t(n) -> n) f(i)}

我们考虑将后面sigma中的 f(i) 中的 f(t(n)) 及t(n)相关的常数项全部提取出来,那么后面就可以提取出 (n-t(n)+1) 个 f(t(n)),常数项的话先暂时用k(n-t(n))表示,提取后剩下的部分就是 g(n-t(n))。

然后g(n) = g(t(n) - 1) + (n-t(n)+1)*f(t(n)) + k(n-t(n)) + g(n-t(n))

如果我们可以处理 k(n-t(n)) 和 g(t(n) - 1) 的话,就可以在复杂度要求内得出解了

我们考虑如何去求 k ,观察后发现 k 函数的实际意义可以表达为 k(n) = sigma {(i = 0 -> n) BitCount(i)}

用和 g 相似的手法,我们也可以把 k 给拆分到只于2的整次幂减1项相关

因为我们常数项的系数就是BitCount()的和

当n=2^a - 1时我们把式子变形得到k(n) = sigma{(i = 1 -> a) C[a][i] * a} = a*2^(a - 1) 就很好处理了

然后我们发现 g 的2的整次幂减1是也可以方便预处理的,也是相似的手法,就不再赘述了

然后就可以预处理f,g,k,然后就可以计算答案了

计算答案时可以从后往前很方便的计算

代码 :

/*
Lelouch vi Britannia here commands you , all of you , die !
*/
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define low(x) ((x)&(-(x)))
#define LL long long
#define eps 1e-9
#define MOD 1000000007
using namespace std;

#define int int
inline int Max(int a,int b) {return a>b?a:b;}
inline int Min(int a,int b) {return a<b?a:b;}
inline int Abs(int a) {return a>0?a:-a;}
inline int Sqr(int a) {return a*a;}
#undef int

#define MAXN 1000006

int n;
LL f[MAXN],g[MAXN],k[MAXN],two[MAXN],md[MAXN],uk[MAXN],ug[MAXN];
char s[MAXN];

void Pre(int n) {
    two[1]=1;g[1]=1;f[1]=1;k[1]=1;f[2]=2;
    for(int i=2;i<=n;i++) two[i]=two[i-1]*2%MOD;
    for(int i=3;i<=n;i++) f[i]=(2*f[i-1]+(i-1)*two[i-1]-1)%MOD;
    for(int i=2;i<=n;i++) k[i]=(k[i-1]*2+two[i])%MOD;
    for(int i=2;i<=n;i++) g[i]=(g[i-1]*2+two[i]*f[i]+k[i-1]*two[i])%MOD;
    for(int i=1;i<=n;i++) {
        md[i]=(md[i-1]+(s[n-i]==‘1‘?two[i]:0))%MOD;
        uk[i]=(uk[i-1]+(s[n-i]==‘1‘?md[i-1]+1+k[i-1]:0))%MOD;
        ug[i]=(ug[i-1]+(s[n-i]==‘1‘?md[i-1]*f[i]%MOD+f[i]+uk[i-1]*two[i]%MOD+g[i-1]:0))%MOD;
    }
}

int main() {
    scanf("%s",s);
    n=strlen(s);
    Pre(n);
    printf("%lld\n",ug[n]);
    return 0;
}
/*
Hmhmhmhm . That‘s right , I am killer.
*/

时间: 2024-10-05 13:37:49

???--???二进制变换的相关文章

2,8,10,16进制之间的转换

我们常用的进制是“十进制”,就是我们日常所说的逢十进一位,类比1+9=10(很简单) 类比十进制二进制i则是逢而进以也就是1+1=10 , 1+1+1=11,1+1+1+1=100, 1+1+1+1+1=101,1+1+1+1+1+1=110. 我们正常是用的数据为十进制,则十进制的数据转换二进制的数据时用短除 如例题所示,余数从下到上写则为二进制代码,读法就是从前往后念并不是十进制的读法,规律由例题可见当商为偶数对应右边的为0,而商为奇数时则对应的为1 十进制转八进制.十进制转16进制  法则

深度自动编码器

深度自动编码器由两个对称的深度置信网络组成,其中一个深度置信网络通常有四到五个浅层,构成负责编码的部分,另一个四到五层的网络则是解码部分. 这些层都是受限玻尔兹曼机(RBM)(注:也可以采用自编码器预训练?),即构成深度置信网络的基本单元,它们有一些特殊之处,我们将在下文中介绍.以下是简化的深度自动编码器架构示意图,下文会作具体说明. 处理基准数据集MNIST时,深度自动编码器会在每个RBM之后使用二进制变换.深度自动编码器还可以用于包含实数数据的其他类型的数据集,此时编码器中的RBM可以改用高

连续受限玻尔兹曼机

连续 RBM 连续 RBM 是受限玻尔兹曼机的一种形式,它通过不同类型的对比散度采样接受连续的输入(也就是比整数切割得更细的数字).这允许 CRBM 处理图像像素或字数向量这类被归一化到 0 到 1 之间的小数的向量. 应该注意,深度学习网络的每一层都需要四个元素:输入.系数.偏置项以及变换(激活算法). 输入是数值数据,是一个来自于前面层(或者原始数据)的向量.系数是通过每个节点层的特征的权重.偏置项确保部分节点无论如何都能够被激活.变换是一种额外的算法,它在数据通过每一层以后以一种使梯度(梯