考慮如何計算f[
l][r
] f[l
][r]
。很顯然,可以分別計算l,
r l,r
的二進位制中1的個數,然後減去(最大公共字首的1的個數)*2。
考慮如何統計每一對l,
r l,r
的最大字首中1的個數,可以用數字dp。記f
[i][
j][1
/0][
1/0]
f [i
][j]
[1/0
][1/
0]
表示前i i
位,最大公共字首中1的個數為
j' role="presentation">jj,
l l
是/否等於
r' role="presentation">rr,
r r
是/否等於
n' role="presentation">n
n的方案數。這樣,所有數對的最大公共字首中1的個數
t t
顯然就是∏(
j∗f[
len]
[j][
0][1
]+f[
len]
[j][
0][0
])' role="presentation">∏(j
∗f[l
en][
j][0
][1]
+f[l
en][
j][0
][0]
)∏(j
∗f[l
en][
j][0
][1]
+f[l
en][
j][0
][0]
),其中le
n len
表示n的位數。
在轉移的時候注意
l l
不能超過
r' role="presentation">rr,
r r
不能超過
n' role="presentation">n
n即可。
要計算所有數對中二進位制中1的個數也可以用類似的方式。
最後,∑nl
=1∑n
r=lf
(l,r
)=n∗
∑二進位制
中1的個
數−t ∑l=
1n∑r
=lnf
(l,r
)=n∗
∑二進位制
中1的個
數−
t時間複雜度:o(
t∗lo
g2n)
o (t
∗log
2n
)
#include#include#include#define ll long long
#define tt 1000000007
#define maxn 66
using namespace std;
inline char nc()
inline ll _read()
int t,a[maxn];
ll n,nn,f[maxn][maxn][2][2],g[maxn][maxn][2];//f[i][j][1/0][1/0]:前i位,最長公共字首中有j個1,l是否等於r,r是否等於n的方案數
//g[i][j][1/0]:前i位,有j個1,是否等於n的方案數
int main()else
for(int i=0;ifor(int j=0;j<=i;j++)
if(a[i+1]==1)else
ll ans=0,sum=0;
//for(int j=1;j<=len;j++)printf("%d %d %d %d\n",f[len][j][0][0],f[len][j][0][1],f[len][j][1][0],f[len][j][1][1]);
for(int i=1;i<=len;i++)(ans+=(f[len][i][0][1]+f[len][i][0][0])%tt
*i%tt)%=tt;
for(int i=1;i<=len;i++)(sum+=(g[len][i][0]+g[len][i][1])*i
%tt)%=tt;
printf("%lld\n",((sum*(n%tt)%tt-ans*2
%tt)%tt+tt)%tt);
}return
0;}
dp 樹狀陣列
給定乙個長度為 n n 的序列 a a 求 a a 有多少個長度為 m m 的嚴格遞增子串行。輸入格式 第一行包含整數 t t t,表示共有 t t 組測試資料。每組資料,第一行包含兩個整數 n n 和 m m。第二行包含 n n 個整數,表示完整的序列 a a。輸出格式 每組資料輸出乙個結果,每個...
數字串 (樹狀陣列)
原題 wannafly挑戰賽15 d 題意 給乙個數字串,每次操作改變乙個位置的數字,求每次操作後,有多少個子串滿足以下要求 長度在區間 l,r 內 首數字 尾數字 解析 對於乙個位置p,求的是乙個sum p r 1到p l 1範圍內數字大於p位置的個數和p l 1到p r 1範圍內數字小於p位置的...
hdu 2227 樹狀陣列 dp
題意是求乙個數列的不遞減的子串行的個數 很顯然,如果只用dp來做的話時間是o n n 因為dp i 為前i個數可能的方案,則狀態轉移方程為dp i sum dp j j 先對num按數來進行排序,這道題因為資料較大 用到了離散化 因為更新是是按原序更新的,及i之前的num j 一定比num i 小,...