題目大意:求區間[l,r]內滿足數x的f(x)<=f(a)的數的個數。對於乙個n位的數(anan-1an-2....a1),f(x)=an*2^(n-1)+an-1*2^(n-2)+...+a1*1.
題解:首先我們肯定要維護乙個狀態sum表示列舉到pos位數的前面的數字的f(x)值,最後判斷一下是否大於f(a)就行了。
因為f(x)最大為4599.所以這樣是存的下的。
但是我們還需要再開一維存預先求出來的f(a),用來記錄每一操作時對應的f(a)。
如果不用的話直接每次操作時都memset會超時。
但是這樣一來空間又不夠了,因此我們需要考慮一種狀態既不需要存f(a),memset又可以在外面執行。
這裡就體現了減去的藝術了。
定義新的狀態為dp[pos][sum]表示列舉到當前pos位,後面還需要湊sum的權值和的個數。
至於為什麼這樣是可行的呢。
我們可以這樣考慮,雖然f(a)是變的,但是每次大的f(a)總會用到小的f(a)。
而小的f(a)不會因為大的f(a)的改變而改變,因此大的sum會用到小的sum,但是小的sum不會因為f(a)的改變而改變。
**實現:
#pragma gcc optimize(2)
#include #include #include #include #include #include #include #include #include #include #include #define pi atan(1.0) * 4
#define e 2.718281828
#define rp(i, s, t) for (register int i = (s); i <= (t); i++)
#define rp(i, t, s) for (register int i = (t); i >= (s); i--)
#define ll __int64
#define ull unsigned long long
#define mst(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define pii pair#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
while (c >= '0' && c <= '9')
return a * b;
}int a[20];
ll dp[20][5005];
ll max;
int num;
ll dfs(int pos,int sum,int lead,int limit)
if(!limit&&!lead) return dp[pos][max-sum]=ans;
return ans;
}ll solve(ll x)
int main()
// printf("%lld\n",max);
printf("case #%d: %lld\n",++kcase,solve(b)-solve(0)+1);
}return 0;
}
HDU 4734 基礎數字dp(遞推)
以前成都賽區的題目。題意很明顯,就是有乙個f x 的函式,然後給你乙個a和b求出在0 b中有多少小於等於f a 的,預處理出來dp i j k 中有多少小於等於k的。這裡採用遞推。因為我太弱了。遞迴總是寫錯。還需慢慢加深理解。ps.很醜。還是推薦遞迴。實在不會遞推也可以。蒟蒻加油!include i...
HDU 4734 基礎數字dp(遞推)
以前成都賽區的題目。題意很明顯,就是有乙個f x 的函式,然後給你乙個a和b求出在0 b中有多少小於等於f a 的,預處理出來dp i j k 中有多少小於等於k的。這裡採用遞推。因為我太弱了。遞迴總是寫錯。還需慢慢加深理解。ps.很醜。還是推薦遞迴。實在不會遞推也可以。蒟蒻加油!include i...
HDU4734,F x (數字DP 優化)
本題思路和dp狀態不難求,比較難的是該怎麼優化。數字dp的優化可參考下面的部落格 簡單的說,一般數字dp的優化有兩種方法 將memset放置在多組資料外面,即程式每執行一次只需memset一次,這種方法要求,題目所給的約束條件是每個數本身的屬性,與輸入無關。相減,這種方法是稍微改變一下狀態,使得題目...