luogu ac通道! (官方資料)
題目描述
小智家裡來了很多的朋友,總共有n個人,站成一排,分別編號為0到n-1,小智要給他們分糖果。但 是有的朋友有一些特殊的要求,有的人要求他左右的兩個人(左邊乙個、右邊乙個,一共2個人)的 糖果數都比他的多,有的人要求他左右的兩個人的糖果數都比他的少。同時小智希望給不同的人分到 的糖果數不相同,並且每個人至少有乙個糖果,同時小智希望分出的糖果個數盡可能的少,現在小智 想知道有多少種分糖果的方法。資料保證不會出現兩個人的要求產生衝突的情況。
輸入格式
第一行三個數n,m,k,分別表示人數,第一種要求的人的個數,k表示第二種要求的人的個數。 接下來m行,每行乙個數x,表示位置x的人要求他左右兩個人的糖果數都比他的多 接下來k行,每行乙個數y,表示位置y的人要求他左右兩個人的糖果數都比他的少
輸出格式
輸出乙個數表示方法數對 1000000007取模的結果。
這道題考慮dp解法。
如何想到用dp解法? 因為題目中要求我們最多有多少種方法,如果乙個個列舉或者求出的話,就會讓我們的時間複雜度分分鐘上去。因此這類題都是套路一般的dp。
首先,看到題目中有兩種要求。一種是讓兩邊的小,一種是讓兩邊的大。
這種要求有一點不好處理的就是,我們總是喜歡直接檢視每乙個點的情況,而不是檢視其旁邊的點情況,這樣很不方便。於是我們轉換一下。
設flagi = 1時,表示第 i 個點小於前乙個點。同樣的,當 flagi = 2時,表示第i個點大於前乙個點。當然,falg = 0時,表示無特殊關係。
然後,設定乙個dp[i][j] 表示由前 i 個數組成的序列且第 i 位為 j 的合法情況數。在規劃的過程中,針對不同的 flag[i],對應不同的狀態轉移,這裡涉及到乙個最後一位數 j 插入序列的思維,可以看做把前邊的每一種排列中大於等於 j 的數 ++,也就可以達到空出 j 這個數將其插入的效果。
在這裡引入乙個 sum[j],表示為前一輪狀態下,最後一位小於等於 j 的情況的和。也就是說,當規劃到第 i 位時,sum[j] 表示前 i - 1 位數組成的序列的合法情況的 dp[i - 1][j] 的字首和。
到這裡,這道題也就可以被我們ac了。我們要求的和就是 sum[n].
ac**:
#include usingnamespace
std;
#define n 100100
#define isdigit(c) ((c)>='0'&&(c)<='9')
const
int mod = (int)1e9 + 7
;inline
intread()
while
(isdigit(c))
return x *s;
}int
flag[n], sum[n], dp[n];
intmain()
for(int i = 1;i <= m; i++)
dp[1] = sum[1] = 1
;
for(int i = 2;i <= n; i++)
else
if(flag[i] == 1
)
else
}for(int j = 1;j <= i; j++)
}cout
<< sum[n]
}
nssl1447 小智的糖果 dp
長度為n nn的序列,m mm個位置要求兩邊都比他大,k kk個位置要求兩邊都比他小。求序列個數。若第x xx個位置為山峰,那麼ax 1 ax 1 a a ax 1 ax 1 我們用upi up i upi 表示第i ii個位置與前面數的大小關係。然後用fi,jf fi,j 表示前i ii個數是1 ...
51nod 1778 小Q的集合
原題連線 題目繞了一點。並沒有直接給出數字形式。而且這個題有好像有很多方法。我也yy了乙個 不過還是題解多效率高 題目中是給定了乙個集合 s 並且有 s n 要說明的是。這個集合是沒有重複元素的集合。這一點很重要 其實不特別說明。一般集合也都沒有重複元素。集合s的子集數量等價於 從 s 中取元素的取...
51nod 1742 開心的小Q
我們由於莫比烏斯函式如果有平方數因子就是0,那麼我們可以列出這樣的式子 sum sum 1 mu d 然後列舉倍數 sum sum rfloor 1 mu d sum f lfloor frac rfloor f x 就表示1 x有多少數有平方因子 可以用容斥得到 f n n sum mu i lf...