「P4996」「洛谷11月月賽」 咕咕咕(數論
題目描述
小 F 是一個能鴿善鵡的同學,他經常把事情拖到最後一天才去做,導致他的某些日子總是非常匆忙。
比如,時間回溯到了 2018 年 11 月 3 日。小 F 望著自己的任務清單:
- 看 iG 奪冠;
- 補月賽題的鍋。
小 F 雖然經常咕咕咕,但他完成任務也是很厲害的,他一次性可以完成剩餘任務的任一非空子集。比如,他現在可以選擇以下幾種中的一種:
- 看 iG 奪冠;
- 補月賽題的鍋;
- 一邊看 iG 奪冠的直播,一邊補鍋。
當然,比賽實在是太精彩了,所以小 F 就去看比賽了。
不過,當金雨從天而降、IG 舉起獎盃之時,小 F 突然心生愧疚——鍋還沒補呢!於是,小 F 的內心產生了一點歉意。
這時小 F 注意到,自己總是在某些情況下會產生歉意。每當他要檢查自己的任務表來決定下一項任務的時候,如果當前他幹了某些事情,但是沒幹另一些事情,那麼他就會產生一定量的歉意——比如,無論他今天看沒看比賽,只要沒有補完月賽的鍋,他都會在選擇任務的時候產生 11 點歉意。小 F 完成所有任務後,他這一天的歉意值等於他每次選擇任務時的歉意之和。
過高的歉意值讓小 F 感到不安。現在,小 F 告訴你他還有 nn 項任務,並告訴你在 mm 種情況中的一種 \mathrm{state}_istatei 的情況下,小 F 會產生 a_iai 點歉意。請你幫忙計算一下,小 F 在那一天所有可能的完成所有任務方式的歉意值之和是多少。
由於答案可能很大,你只需要輸出答案對 998244353998244353 取模即可。
輸入輸出格式
輸入格式:
輸入一行兩個整數 n, mn,m,表示有 nn 項任務,在 mm 種情況中下小 F 會產生歉意值。
輸入接下來 mm 行,每行有一個長度為 nn 的 0-10−1 串 \mathrm{state}_istatei 和一個歉意值 a_iai,\mathrm{state}_{i, j}statei,j 為 0/10/1 表示第 jj 項任務此時沒做 / 已經做了。
詳情請參考樣例和樣例解釋。
輸出格式:
輸出一行一個整數,表示小 F 在那一天所有可能的完成任務方式的歉意值之和對 998244353998244353 取模的結果。
輸入輸出樣例
輸入樣例#1: 複製2 2 00 1 10 1輸出樣例#1: 複製
4輸入樣例#2: 複製
3 4 000 16 001 9 110 4 111 1輸出樣例#2: 複製
260
說明
樣例 1 解釋:
0-10−1 串中第一個數字表示小 F 看沒看比賽,第二個數字表示小 F 補沒補鍋。
我們用 \varnothing∅ 表示小 F 什麼都沒幹,AA 表示小 F 看了比賽,BB 表示小 F 補了鍋,那麼所有會產生愧疚的方式如下:
\varnothing: 1∅:1
\{A\}:1{A}:1
那麼所有可能的選擇如下:
\varnothing\rightarrow\{A\}\rightarrow\{A,B\}:2∅→{A}→{A,B}:2
\varnothing\rightarrow\{B\}\rightarrow\{A,B\}:1∅→{B}→{A,B}:1
\varnothing\rightarrow\{A,B\}:1∅→{A,B}:1
所以答案是 2 + 1 + 1 = 42+1+1=4。
資料範圍
保證出現的 \mathrm{state}_istatei 互不相同。
對於所有資料,有 1 \leq n \leq 201≤n≤20, 1 \leq m \leq \min(2 ^ n, 10 ^ 5), 1 \leq a_i \leq 10 ^ 51≤m≤min(2n,105),1≤ai≤105。
題解
題意
首先給定$m$個長為$n$的串,和踩中每個需付的代價。
定義每次操作從$\underbrace{000....00}_{n}$開始,每步可以任選至少一個$0$變成$1$,當所有串變成$\underbrace{111....11}_{n}$時,操作結束。
在操作過程中,如果在某時刻序列和之前給定的序列相同,那麼要付給定序列的代價。
問在這數不清的不同操作都做完之後(兩次操作相同當且僅當變換過程完全相同),一共要付的代價,對$998244353$取模。
哇這個題真實的難讀懂啊qwq
以下分析
先來考慮對於一個給定串$s$,有多少個操作(設為$ans$)會撞上它。
可以注意到,答案跟數字的位置無關,所以我們可以先把串抽象出來,數出有$c$個$1$,$(n-c)$個$0$。
那麼這$c$個$1$,可能是由$c-1$個$1$的串轉移而來,可能是$c-2,c-3......0$個$1$的串轉移而來。
dp!
設$f[i]$為轉移成$i$個$1$的方案數。
轉移方程:$f[i]=\sum_{j=0}^{j-1}(f[j]*C_{i}^{j})$。
其中$C_i^j$是因為有$C_i^j$種方式從$j$個$1$轉移成$i$個$1$。(在$i$個裡面欽定$j$個為原有的$1$的方案數為$C_i^j$)
那麼從$000.....0$轉移到$s$的方案數就為$f[c]$。
而從$s$轉移到$111.....1$的方案數可以倒著思考:從$111.....1$轉移到$s$,有$(n-c)$個$1$變成了$0$對叭。
所以可以直接操起求過的$f$陣列,從$s$轉移到全$1$串的方案數就為$f[n-c]$。
然後用乘法原理乘起來,就得到了會經過串$s$的運算元,再乘上串$s$的單次代價就是這個串造成的總代價了。
最後把$m$個串的代價加起來就是答案。
1 /* 2 qwerta 3 P4996 咕咕咕 Accepted 4 100 5 程式碼 C++,0.6KB 6 比賽 【LGR-055】洛谷11月月賽 7 提交時間 2018-11-04 11:58:31//下考前幾十秒發現自己忘開long long,太真實了qwq 8 耗時/記憶體 108ms, 804KB 9 */ 10 #include<iostream> 11 #include<cstdio> 12 using namespace std; 13 #define LL long long//一年OI一場空,不開long long見祖宗 14 const int mod=998244353; 15 LL f[23]; 16 char s[23]; 17 LL je(int x)//返回x!(因為20!沒爆long long就直接亂搞了 18 { 19 LL ans=1; 20 while(x) 21 { 22 ans*=x; 23 x--; 24 } 25 return ans; 26 } 27 LL C(int q,int w)//返回C(q,w) 28 { 29 return je(q)/je(w)/je(q-w); 30 } 31 int main() 32 { 33 ios::sync_with_stdio(false); 34 int n,m; 35 cin>>n>>m; 36 f[0]=1;//初始化 37 //先把f預處理出來 38 for(int i=1;i<=n;++i) 39 { 40 for(int j=0;j<i;++j) 41 { 42 f[i]+=C(i,j)*f[j]%mod; 43 f[i]%=mod; 44 } 45 } 46 LL ans=0; 47 for(int i=1;i<=m;++i) 48 { 49 cin>>s; 50 int c=0;//c為s中1的個數 51 for(int j=0;j<n;++j) 52 c+=s[j]-'0'; 53 int v;//這個串的單次代價 54 cin>>v; 55 ans+=(LL)f[c]*f[n-c]%mod*v%mod; 56 ans%=mod; 57 } 58 cout<<ans; 59 return 0; 60 }