1. 程式人生 > 實用技巧 >CSP/NOIP新賽制內部挑戰賽2 A. 二進位制王國

CSP/NOIP新賽制內部挑戰賽2 A. 二進位制王國

sub1 (50pts)

設f[i][j] 為用前i種紙幣,還需要總金額為j的方案數

列舉第i個紙幣用了k 張,從f[i−1][j+k∗(2^i)] 轉移


時間複雜度:O(n^2*log n)

sub2 (85pts)

其實就是無限揹包的問題

直接 f[i][j]=f[i−1][j]+f[i][j+(2^i)]


第一維顯然可以壓縮掉
時間複雜度:O(n*log n)

sub3 (95pts)

面值為1 的紙幣考慮完後,j 為奇數的位置就不可能轉移到答案了
面值為2 的紙幣考慮完後,j mod 4 != 0 的位置就不可能轉移到答案了
後面的以此類推
所以轉移有效位置即可

時間複雜度:O(N)

標算

其上一種演算法的空間會炸、

觀察轉移的過程,可以發現程式等價於每次轉移後把座標為奇數的位置刪除,然後把n/ = 2
另外容易發現,使用面值為1 的紙幣時的轉移相當於把陣列的每個位置賦值成1
那麼我們可以手動完成面值為1 的紙幣的轉移,時空常數均除以2

注意哈:面值為0也是一種方案!!

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e8+5;
unsigned int f[maxn];
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out
","w",stdout); f[1]=2; int n; scanf("%d",&n); if(!n) { printf("1"); return 0; } n>>=1; for(int i=2;i<=n;i++) f[i]=f[i-1]+f[i>>1]; printf("%u",f[n]); return 0; }