牛客IOI周賽27-提高組C題題解
阿新 • • 發佈:2021-07-10
原題連結
思路:
我們來看一下第i個數字 & 第i + 1 個數字 = 第i個數字有什麼可探究的性質。
顯然:第i個數字數字第bit位上是1,說明i + 1往後的所有數第bit位上也是1,
而第bit位為1代表著2的某個次冪。
更一般的,原題等價於將m拆分成若干個2的次冪的和,其中同種類的2次冪的個數≤n,求劃分數。
由於資料範圍為5e6
而2^23 > 5e6
因此,我們可以將問題轉化成,用上限為n的前23個2的冪次,組成m的方案數
則這就是一個多重揹包求方案數的模板。
程式碼如下:
#include <bits/stdc++.h> using namespace std; #define ll long long const ll mod = 1e9 + 7; ll dp[5000010]; ll sz[24] = {0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304}; ll n, m; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; //多重揹包有上限求方案數的模板 dp[0] = 1; for (int i = 1 ; i <= 23 ; i++) { for (int j = sz[i] ; j <= m ; j++) { dp[j] = (dp[j] + dp[j - sz[i]]) % mod; } for (int j = m ; j >= (n + 1) * sz[i] ; j--) { dp[j] = (dp[j] - dp[j - (n + 1) * sz[i]] + mod) % mod; } } cout << dp[m] << "\n"; return 0; }