1. 程式人生 > >「P4996」「洛谷11月月賽」 咕咕咕(數論

「P4996」「洛谷11月月賽」 咕咕咕(數論

題目描述

小 F 是一個能鴿善鵡的同學,他經常把事情拖到最後一天才去做,導致他的某些日子總是非常匆忙。

比如,時間回溯到了 2018 年 11 月 3 日。小 F 望著自己的任務清單:

  1. 看 iG 奪冠;
  2. 補月賽題的鍋。

小 F 雖然經常咕咕咕,但他完成任務也是很厲害的,他一次性可以完成剩餘任務的任一非空子集。比如,他現在可以選擇以下幾種中的一種:

  1. 看 iG 奪冠;
  2. 補月賽題的鍋;
  3. 一邊看 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-101 串 \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-101 串中第一個數字表示小 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 201n20, 1 \leq m \leq \min(2 ^ n, 10 ^ 5), 1 \leq a_i \leq 10 ^ 51mmin(2n,105),1ai105。

題解 

題意

首先給定$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 }