noip2019提高組 Emiya 家今天的飯

2022-05-03 06:03:11 字數 1422 閱讀 9302

題面

這裡思路

一道很妙的dp題,首先可以發現至多有一種主要食材被選超過t/2次,所以考慮用容斥:合法方案=總方案數-σ每行的不合法方案數。顯然:求出確定的某一列不合法的方案數比求出每一行都合法的方案數要簡單得多(範圍減小,限制更明確)。

..................這也是容斥的基本思路:正難則反....................

根據這個可以列出樸素的dp轉移方程:令f[i][j][k]表示前i行在當前第p列中選了j個,其它列中選了k個;s[i]表示第i行總共有多少道菜。

f[i][j][k]=f[i-1][j][k]+a[i][p]*f[i-1][j-1][k]+(s[i]-a[i][k])*f[i-1][j][k-1]

但是方程轉移是n^3的,加上列舉每一列,總時間複雜度是o(m*n^3)的,很明顯過不了這題。接下來考慮優化:

再仔細讀題,不合法的方案是選當前列次數超過了選其他列的個數,也就是說,我們只需要記錄j和k的相對數量,於是可以將這兩維壓成一維。令f[i][j]表示前i列選當前行比其他行多j次的方案數。轉移方程基本同上。

剩下的問題就是如何求總方案:本人比較蒟蒻地又用了乙個dp。g[i][j]表示前i行選了j次的方案數。g[i][j]=g[i-1][j]+g[i-1][j-1]*s[i];總方案即σg[n][i]。但其實有更簡單的方法:總方案=π(s[i]+1)-1;即每行選任意一道菜,也可不選。但要減去總共選0道菜的方案。

**幾個細節:

*列舉每列時記得清空f陣列

*注意ans-f[n][i]時因為取了模可能減為負數

*f[i][j]的j這一維可能為負數,為了好處理,將j變為j+n;轉移時只需從n-i列舉到n+i,容斥時只需從n+1列舉到n+n即可

1 #include2

#define ll long long

3using

namespace

std;

4const

int inf=998244353;5

long

long f[105][305],g[105][105],s[105

],ans;

6int a[105][2005];7

intmain()15}

16 g[0][0]=1;17

for(i=1;i<=n;i++)

22for(i=1;i<=n;i++)

23 ans=(ans+g[n][i])%inf;

24for(k=1;k<=m;k++)31}

32for(i=n+1;i<=n+n;i++)

33 ans=(ans-f[n][i]+inf)%inf;34}

35 printf("

%lld

",ans);

36return0;

37 }

view code

NOIP2019提高組模擬 購物(題解)

強烈譴責 這道題不符合生活常識,優惠卷面額的作用竟然不是扣多少錢的而是扣到多少錢,巨坑!關鍵是樣例還能過,mmp 題解 這道題可以採用貪心的思想,把優惠了的和沒優惠的所以合成乙個陣列在一起算,一起sort一下,然後就要堅持乙個商品只能買一次的原則,將每個要選的優惠後的 標記一波,不選它的原來 而且要...

NOIP2023年提高組複賽上機試題

通常,人們習慣將所有 n 位二進位制串按照字典序排列,例如所有 2 位二進位制串按字典序從小到大排列為 00,01,10,11。格雷碼 gray code 是一種特殊的 n 位二進位制串排列法,它要求相鄰的兩個二進位制串間恰好有一位不同,特別地,第乙個串與最後乙個串也算作相鄰。所有 2 位二進位制串...

NOIP2019普及組紀念品

不廢話了,傳送門 p5662 難點在於如何處理擁有的紀念品。我們不妨在當天交易之前把持有的紀念品全部賣出,但你發現你不知道這一天的紀念品如何儲存,我們發現在每一天的最後把購置的紀念品全部以第二天的 賣出,就相當於在第二天一開始賣出,那麼為什麼一定在全部交易完後才賣呢?我們完全可以在買的同時用第二天的...