NOI Online 3 提高組 優秀子串行

2021-10-06 14:18:43 字數 1671 閱讀 3716

點此看題

首先有乙個樸素dpdp

dp,因為每個數字都只會最多出現1

11次,而且出現數字相同的不同情況最後也可以一起算答案(和一定),那麼我們只需要統計出方案數,dp[

i]

dp[i]

dp[i

]為二進位制位出現的裝壓為i

ii,轉移列舉包含i

ii的狀態j

jj,設a[i

]a[i]

a[i]

為值i

ii出現次數,0

00需要單獨考慮,轉移為:

d p[

j]=d

p[j⊕

i]×a

[i

]dp[j]=dp[j\oplus i]\times a[i]

dp[j]=

dp[j

⊕i]×

a[i]

這樣做o

(min⁡(

a,n)

a)

o(\min(a,n)a)

o(min(a,

n)a)

,優化j

jj的列舉方式,找到大於等於i

ii的全1

11的數,那麼我們可以拿到i

ii在這個集合下的補集,那麼列舉這個補集的子集,就是j

jj比i

ii多出來的一部分,這樣轉移的複雜度是o(3

k)

o(3^k)

o(3k)(2

k>

a2^k>a

2k>a)

#include

#include

using

namespace std;

const

int m =

300005

;const

int jzm =

1e9+7;

intread()

int n,m,k,mx,cnt,ans,a[m]

,b[m]

,dp[m]

,phi[m]

,p[m]

;void

sieve

(int n)

for(

int j=

1;j<=cnt && i*p[j]

<=n;j++

) phi[i*p[j]

]=phi[i]

*phi[p[j]];

}}}int

main()

m=1;

while

(m<=mx)

m*=2

;sieve

(m);

m--;dp[0]

=1;for

(int i=

1;i<=mx;i++)}

for(

int i=

0;i<=m;i++

) ans=

(ans+

1ll*dp[i]

*phi[

1+i]

)%jzm;

for(

int i=

1;i<=k;i++

) ans=

2ll*ans%jzm;

printf

("%d\n"

,ans)

;}

NOI Online 3 提高組 優秀子串行

傳送 這題剛開始看到那麼多式子,確實沒啥思路。但是再仔細想一想會發現挺有意思的。因為 b 序列的限制,每乙個 b i 的二進位制中的1必定只有他自己有,那麼 sum b i 就是把他們按位與起來。我們令 dp s 表示 sum b i s 的 b 序列個數,那麼答案就是 dp i sum phi i...

NOI Online 3 提高組 水壺

在乙個長度為 n 的序列中求出長度為 k 1 的最大子段。本題唯一的需要注意的一點是當 k n 時要輸出所有數的和,像我的考場 scanf d d n,k k if k n k n for int i 1 i n i scanf d a i for int i 1 i k i op a i for ...

NOI Online 3 提高組 魔法值

我是真沒想到可以用 flo yd floyd floy d 好吧其實也不是正宗的吧 感覺這個演算法已經被我遺忘了 qwq qwqqw q。結果考場上把快速冪又打爆了 定義 to i j k to i j k to i j k 為 i ii 到 j jj 的路徑長度為 2 k2 k 2k的方案總數,d...