1.被三整出的子序列 题目链接
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
区间dp,像前面打过的一个cf题
dp[i][j][k]表示子序列第i与j个之间除三的余数为k的子序列个数
从第一个数开始穷举区间,不断往区间内加数,若加入的后一个数是3的倍数,那么3的倍数的子序列个数就是不加这个数之前区间内个数的2倍+1,(加上这个数构成的新序列就是不加前的所有序列个数,所以是两倍,再加上本身)其它余数同理
#include <bits/stdc++.h>
using namespace std;
int dp[55][55][5];
const int mod =1e9+7;
int main (){
string str;
cin>>str;
for(int i=str.length();i>=0;i--){
str[i]=str[i-1];
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=str.length();i++){
dp[i][i][(str[i]-'0')%3]=1;
}
for(int i=1;i<=str.length();i++){
for(int j=i;j<str.length();j++){
if((str[j+1]-'0')%3==0){
dp[i][j+1][0]=2*dp[i][j][0]+1;
dp[i][j+1][1]=2*dp[i][j][1];
dp[i][j+1][2]=2*dp[i][j][2];
}
else if((str[j+1]-'0')%3==1){
dp[i][j+1][0]=dp[i][j][2]+dp[i][j][0];
dp[i][j+1][1]=dp[i][j][1]+dp[i][j][0]+1;
dp[i][j+1][2]=dp[i][j][1]+dp[i][j][2];
}
else if((str[j+1]-'0')%3==2){
dp[i][j+1][0]=dp[i][j][1]+dp[i][j][0];
dp[i][j+1][1]=dp[i][j][2]+dp[i][j][1];
dp[i][j+1][2]=dp[i][j][0]+dp[i][j][2]+1;
}
for(int k=0;k<3;k++){
dp[i][j+1][k]%=mod;
}
}
}
cout<<dp[1][str.length()][0]<<endl;
return 0;
}
2.删括号
链接:https://ac.nowcoder.com/acm/problem/21303
来源:牛客网
给你一个合法的括号序列s1,每次你可以删除一个"()"
你可以删除0个或者多个"()"
求能否删成另一个括号序列s2
#include <bits/stdc++.h>
using namespace std;
int dp[105][105][105];
int main (){
string str1,str2;
cin>>str1>>str2;
int n =str1.length();
int m =str2.length();
for(int i=n;i>0;i--){
str1[i]=str1[i-1];
}
for(int i=m;i>0;i--){
str2[i]=str2[i-1];
}
dp[0][0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=n;k++){
if(dp[i][j][k]){
if(!k&&str1[i+1]==str2[j+1]) dp[i+1][j+1][k]=1;
if(str1[i+1]=='(') dp[i+1][j][k+1]=1;
else if(k) dp[i+1][j][k-1]=1;
}
}
}
}
puts(dp[n][m][0]?"Possible":"Impossible");
return 0;
}