日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【牛客 - 21302】被3整除的子序列(线性dp)

發布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【牛客 - 21302】被3整除的子序列(线性dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題干:

給你一個長度為50的數字串,問你有多少個子序列構成的數字可以被3整除
答案對1e9+7取模

輸入描述:

輸入一個字符串,由數字構成,長度小于等于50

輸出描述:

輸出一個整數

示例1

輸入

復制

132

輸出

復制

3

示例2

輸入

復制

9

輸出

復制

1

示例3

輸入

復制

333

輸出

復制

7

示例4

輸入

復制

123456

輸出

復制

23

示例5

輸入

復制

00

輸出

復制

3

備注:

n為長度 子任務1: n <= 5 子任務2: n <= 20 子任務3: 無限制

解題報告:

? 不難發現長度為50的串最大可以到達的數字就是50*9 = 450 ,所以dp[i][j]代表前i個數 可以組成的和為j的方法數。然后分選和不選兩種決策轉移就行了。

AC代碼:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #include<cctype> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; char s[MAX]; ll dp[55][555];//dp[i][j]代表前i個數 可以組成的和為j的方法數。 const ll mod = 1e9 + 7; int f(char c) {return c - '0'; } int main() {//dp[0][0]=1;cin>>(s+1);int len = strlen(s+1);for(int i = 1; i<=len; i++) { // dp[i][f(s[i])] = 1;for(int j = 0; j<555; j++) {dp[i][j] = dp[i-1][j];if(j == f(s[i])) dp[i][j]++;if(j >= f(s[i])) dp[i][j] += dp[i-1][j-f(s[i])];dp[i][j] %= mod;}}//printf("**%d\n",dp[len][3]);ll ans = 0;for(int j = 0; j<555; j++) if(j % 3 == 0) ans = (ans + dp[len][j]) % mod;printf("%lld\n",ans);return 0 ;}

AC代碼2:(這樣寫更簡短一點)

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #include<cctype> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; char s[MAX]; ll dp[55][555];//dp[i][j]代表前i個數 可以組成的和為j的方法數。 const ll mod = 1e9 + 7; int f(char c) {return c - '0'; } int main() {//dp[0][0]=1;cin>>(s+1);int len = strlen(s+1);for(int i = 1; i<=len; i++) { // dp[i][f(s[i])] = 1;for(int j = 0; j<555; j++) {dp[i][j] = dp[i-1][j];if(j >= f(s[i])) dp[i][j] += dp[i-1][j-f(s[i])];dp[i][j] %= mod;}dp[i][f(s[i])]++;}ll ans = 0;for(int j = 0; j<555; j++) if(j % 3 == 0) ans = (ans + dp[len][j]) % mod;printf("%lld\n",ans); return 0 ;}

?注意到這題不能直接想當然的dp[0][0]=0,,如果是這樣的話那代碼就更簡短了,,為什么不能這樣呢?因為這題中 0 也算狀態之一,所以不能這樣來初始化,考慮一般寫dp[0][0]的影響,無非就是加上自己的一次。所以我們雖然不寫dp[0][0]=0了,但是相應的把這個狀態自己加上就行了。注意AC代碼2,這一句++必須放在for之后,不能放在for之前,因為不然后面for中那個等號就把這個++ 操作給覆蓋了。(其實放在for之前也行,但是就得變成dp[i][j] += dp[i-1][j];了?)

同時通過觀察我們發現,最后答案只跟模數有關,所以我們直接記錄模數也可以。

AC代碼3:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #include<cctype> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; char s[MAX]; ll dp[55][3];//dp[i][j]代表前i個數 可以組成的和為j的方法數。 const ll mod = 1e9 + 7; int f(char c) {return c - '0'; } int main() {//dp[0][0]=1;cin>>(s+1);int len = strlen(s+1);for(int i = 1; i<=len; i++) { // dp[i][f(s[i])] = 1;for(int j = 0; j<3; j++) {dp[i][j] = dp[i-1][j];dp[i][j] += dp[i-1][(j+15-f(s[i]))%3];dp[i][j] %= mod;}dp[i][f(s[i])%3]++;}ll ans = dp[len][0];//for(int j = 0; j<555; j++) if(j % 3 == 0) ans = (ans + dp[len][j]) % mod;printf("%lld\n",ans%mod); return 0 ;}

?

總結

以上是生活随笔為你收集整理的【牛客 - 21302】被3整除的子序列(线性dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。