日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF750G New Year and Binary Tree Paths(数位dp二进制+数学)

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF750G New Year and Binary Tree Paths(数位dp二进制+数学) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CF750G New Year and Binary Tree Paths

  • description
  • solution
  • code

description

題目鏈接

一顆無窮個節點的完全二叉樹。

求有多少條樹上的簡單路徑編號和為 s。

s≤1e15s\le 1e15s1e15

solution

  • 一條單鏈的情況

    考慮從節點xxx開始走一條節點個數是hhh的鏈(鏈長為h?1h-1h?1

    假設從上往下一直往左子樹走【x,2x,4x,8x...x,2x,4x,8x...x,2x,4x,8x...

    則貢獻為x∑i=0h?12i=(2h?1)xx\sum_{i=0}^{h-1}2^i=(2^h-1)xxi=0h?1?2i=(2h?1)x

    若鏈從下往上的第i∈[1,h)i\in[1,h)i[1,h)個點是右兒子,則會給標號和帶來獨立的∑j=0i?12j=2i?1\sum_{j=0}^{i-1}2^j=2^i-1j=0i?1?2j=2i?1貢獻

    可以解出,xxx的取值只能是?s2h?1?\lfloor\frac{s}{2^h-1}\rfloor?2h?1s??

    證明:假設取x?1x-1x?1,且這條長hhh的鏈全走右子樹的貢獻是:

    (2h?1)(x?1)+∑i=1h?1(2i?1)=2hx?x?2h+1+2h?1?h=(2h?1)x?h<(2h?1)x(2^h-1)(x-1)+\sum_{i=1}^{h-1}(2^i-1)=2^hx-x-2^h+1+2^h-1-h=(2^h-1)x-h< (2^h-1)x(2h?1)(x?1)+i=1h?1?(2i?1)=2hx?x?2h+1+2h?1?h=(2h?1)x?h<(2h?1)x

    這已經是最大的不是選xxx產生的可能貢獻了,所以只能是xxx

    這里同樣經典的,可以判斷能否用【1,3,...,2h?1?11,3,...,2^{h-1}-11,3,...,2h?1?1】構造出s?(2h?1)xs-(2^h-1)xs?(2h?1)x,先用大的開始嘗試(從最大的往小的開始一個一個試,有點類似倍增的思想不斷逼近直到相等的感覺)

  • 分叉情況(兩條子鏈在根節點拼接)

    假設根節點為xxx,設xxx左兒子開始向下的鏈長度為h1h_1h1?,右兒子開始向下的鏈長度為h2h_2h2?,枚舉h1,h2∈[1,log2s]h_1,h_2\in[1,\text{log}_2^s]h1?,h2?[1,log2s?]

    假設這兩條鏈都往各自的左兒子走,貢獻是:

    x+2x(2h1?1)+(2x+1)(2h2?1)=(2h1+1+2h2+1?3)x+2h2?1x+2x(2^{h_1}-1)+(2x+1)(2^{h_2}-1)=(2^{h_1+1}+2^{h_2+1}-3)x+2^{h_2}-1x+2x(2h1??1)+(2x+1)(2h2??1)=(2h1?+1+2h2?+1?3)x+2h2??1

    同理,xxx的位置也是唯一確定的,即?s?(2h2?1)2h1+1+2h2+1?3?\lfloor\frac{s-(2^{h_2}-1)}{2^{h_1+1}+2^{h_2+1}-3}\rfloor?2h1?+1+2h2?+1?3s?(2h2??1)??

    t=st=st=s減去上面的貢獻

    同時,考慮怎么用各自某一層走右兒子產生的貢獻【1,3,...,2h1?1;1,3,...,2h2?11,3,...,2^{h_1}-1;1,3,...,2^{h_2}-11,3,...,2h1??1;1,3,...,2h2??1】來構造出ttt,轉換一下考慮用【2,22,...,2h1;2,22,...,2h22,2^2,...,2^{h_1};2,2^2,...,2^{h_2}2,22,...,2h1?;2,22,...,2h2?】來湊ttt

    枚舉選了nnn個數,判斷能不能用這些數湊出t+nt+nt+n

    • 這里的實現考慮使用數位dpdpdpO(h1h2)O(h_1h_2)O(h1?h2?)求出結果

      fi,j,k:f_{i,j,k}:fi,j,k?:iiih1h_1h1?h2h_2h2?兩條鏈的狀態一共選了jjj222的次方【可能選了222^2222i?1...2^{i-1}...2i?1...,反正一共選了jjj個】,是否有進位k=1/0k=1/0k=1/0的方案數

      對于每一位枚舉h1h_1h1?鏈和h2h_2h2?鏈上的選擇情況s1,s2s_1,s_2s1?,s2?

      注意到,如果i=h1i=h_1i=h1?,這一位是不能選111【表示進位】的,h2h_2h2?同理

      則可以得到轉移方程:f[i+1][j+s1+s2][s1+s2+k2]=∑f[i][j][k](s1+s2+k≡?t+n2i(mod2)?)f[i+1][j+s_1+s_2][\frac{s_1+s_2+k}{2}]=\sum f[i][j][k]\quad\Big(s_1+s_2+k\equiv \lfloor\frac{t+n}{2^i}\pmod 2\rfloor\Big)f[i+1][j+s1?+s2?][2s1?+s2?+k?]=f[i][j][k](s1?+s2?+k?2it+n?(mod2)?)

時間復雜度為O(log5s)O(\text{log}^5s)O(log5s)

code

#include <cmath> #include <cstdio> #include <cstring> #define maxn 60 #define int long long int s, m, now; int f[2][maxn << 1][2], mi[maxn];int calc( int goal, int q, int h1, int h2, int cnt ) {memset( f[now], 0, sizeof( f[now] ) );f[now][0][0] = 1;for( int i = 1;i <= log2( goal ) + 1;i ++ ) {int d = goal >> i & 1;now ^= 1;memset( f[now], 0, sizeof( f[now] ) );for( int j = 0;j <= ( i - 1 << 1 );j ++ ) //到i-1及以前可以一共選了[0,(i-1)*2]個數 左兒子(h1)鏈的選擇和右兒子(h2)鏈的選擇 for( int k = 0;k <= 1;k ++ )if( f[now ^ 1][j][k] )for( int s1 = 0;s1 <= 1;s1 ++ )if( ! s1 or i < h1 )for( int s2 = 0;s2 <= 1;s2 ++ )if( ! s2 or i < h2 )if( ( k + s1 + s2 ) % 2 == d ) //判斷同余 f[now][j + s1 + s2][( k + s1 + s2 ) / 2] += f[now ^ 1][j][k];}return f[now][cnt][0]; }signed main() {int ans = 0;scanf( "%lld", &s );mi[0] = 1;for( int i = 1;i < 60;i ++ ) {mi[i] = mi[i - 1] << 1;if( mi[i] > s and mi[i - 1] <= s ) m = i;}for( int i = 1;i <= m;i ++ ) { //單鏈的構造 int x = s / ( mi[i] - 1 );if( x <= 0 ) continue;int t = s - x * ( mi[i] - 1 );for( int j = i - 1;~ j;j -- )if( t >= mi[j] - 1 ) t -= mi[j] - 1;if( ! t ) ans ++;}for( int h1 = 1;h1 <= m;h1 ++ )for( int h2 = 1;mi[h2] - 1 <= s;h2 ++ ) {int x = ( s - mi[h2] + 1 ) / ( mi[h1 + 1] + mi[h2 + 1] - 3 );if( x <= 0 ) continue;int t = ( s - mi[h2] + 1 ) - x * ( mi[h1 + 1] + mi[h2 + 1] - 3 );if( ! t ) { ans ++; continue; }if( h1 == 1 and h2 == 1 ) { ans += ( t == 5 * x + 1 ); continue; } //x 2x 2x+1 -> 5x+1for( int n = 1;n <= h1 + h2;n ++ ) //枚舉選了n個右兒子 if( ( ( t + n ) & 1 ) == 0 ) ans += calc( t + n, x, h1, h2, n );}printf( "%lld\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的CF750G New Year and Binary Tree Paths(数位dp二进制+数学)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。