講數字dp,然後發現自己學暴了,這裡挑幾道有意思的題目記錄一下,以免將來死得太慘。
題目傳送門
定義 windy 數為滿足相鄰兩位差值 \(\le 2\) 的數,給出 \(l,r\) ,求出 \([l,r]\) 內有多少 windy 數。
\(l,r\le 2\times 10^9\)
我™ 這樣乙個板子題調了乙個小時,果然是我自己菜爆了。。。
我們可以設 \(dp[i][x]\) 表示確定了前 \(i\) 位並且第 \(i\) 位為 \(x\) 時的合法方案數,然後直接記憶化搜尋就好了。下面是一些數字 dp 的細節
原因就是這兩種情況會限制後面幾位的選擇。
#include using namespace std;
#define int register int
#define maxn
template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}
template inline void read (t &t,args&... args)
template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int len,nnum[11],dp[11][10];
int abs (int x)
int dfs (bool up,bool zero,int now,int x)
int calc (int n)
signed main()
題目傳送門
定義乙個數字與 \(7\) 有關當且僅當一下幾種情況:
給出 \([l,r]\) ,求出該區間內與 \(7\) 無關的數字的平方和。
\(l\le r\le 10^\),答案對 \(10^9+7\) 取模。
顯然我們沒有辦法直接搞了。但是我們發現假設當前位為 \(x\) ,後面為 \(y\) ,那麼答案就是 \((x+y)^2=x^2+2xy+y^2\) ,然後我們發現 \(\text =x^2\times \sum+ 2x\times y+\sum y^2\) ,然後我們直接維護合法方案數、合法方案的數字和、合法數字的平方和即可。
#include using namespace std;
#define int register int
#define mod 1000000007
#define int long long
template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}
template inline void read (t &t,args&... args)
template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int len,pw[19],nnum[19];
int mul (int a,int b)void mul (int &a,int b)
int dec (int a,int b)void dec (int &a,int b)
int add (int a,int b)void add (int &a,int b)
struct node
}dp[19][7][7];
node dfs (bool lim,int now,int sum1,int sum2)
if (!lim && dp[now][sum1][sum2].exi) return dp[now][sum1][sum2];
int up = lim ? nnum[now] : 9;node res;res.clear();
for (int i = 0;i <= up;++ i)
if (!lim) dp[now][sum1][sum2] = res,dp[now][sum1][sum2].exi = 1;
return res;
}int calc (int n)
signed main()
return 0;
}
題目傳送門
給出 \(l,r,k\) ,將 \([l,r]\) 劃分成某些段,使得每一段上面的編號的每位數字之和不小於 \(k\) 並且盡可能小。求出分成的段數。
\(l\le r\le 10^,k\le 1000\)
為了更好幫助理解題意,比如 \(l=40,k=11\) ,那麼 \(40,41,42\) 就會被劃分成一段,因為 \(4+0+4+1+4+2\ge 11\) 而且 \(4+0+4+1<11\)。
私認為是很巧妙的一道題。我們可以考慮設 \(dp[i][s1][s2]\) 表示考慮第 \(i\) 位當前編號,\(s1\) 為當前編號產生的每位數字之和,\(s2\) 表示已經劃分出來的貢獻。然後我們就可以進行合併,具體見**。
#include using namespace std;
#define int register int
#define int long long
template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}
template inline void read (t &t,args&... args)
template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int l,r,k,tmp,lnum[19],rnum[19];
struct node
node (int _a,int _b,bool _exi)
}dp[20][185][1010];
void merge (node &x,node y)
node dfs (bool lim1,bool lim2,int now,int sum,int rem)
else
if (!lim1 && !lim2) dp[now][sum][rem] = ans,dp[now][sum][rem].exi = 1;
return ans;
}signed main()
2020 08 05 集訓題目題解
題目傳送門 給出乙個長度為 n 的數列 a 有 m 次操作,每次操作分別為以下兩種 n,m le 5 times 10 4 其實我們可以發現乙個事情,最後 c bmod varphi 1 varphi 1 bmod varphi p varphi p 然後我們就發現到了一定程度之後再加上 c 都不會...
2022 02 06 集訓題解
不難注意到的是,我們假設 f i 為 i 之前 le a i 的值的個數,那麼我們需要滿足 sum i f i sum i min i,a i 又因為我們可以知道 f i le min i,a i 所以我們對於每乙個 i 都有 f i min i,a i 考慮如何構造這樣的 a 可以發現,我們選了乙...
2022 04 04 集訓題解
小 w 的手上有一顆 n 個節點的二叉搜尋樹,裡面有從 1 到 n 這 n 個數字。二叉搜尋樹即為中序遍歷恰好為 1 到 n 的二叉樹 現在你想知道這棵樹的形態。但是小 w 不會直接告訴你,只允許你詢問以某個點為根的子樹是否恰好包含 l,r 中的所有點。你需要在 2 times n 次查詢之內得到整...