1005-交通管控
状压dp,把所有情况用一个三进制数表示,每一个字母分别用数字表示 A = 0 , B = 1 , C = 2 A=0,B=1,C=2 A=0,B=1,C=2。
例如:
C
A
B
C
CABC
CABC 转换为数字表示
2012
2012
2012(这是一个三进制数)。
接着将三进制数
2012
2012
2012 转换为十进制数:
2
∗
3
3
+
0
∗
3
2
+
1
∗
3
1
+
2
∗
3
0
=
59
2*3^3+0*3^2+1*3^1+2*3^0=59
2∗33+0∗32+1∗31+2∗30=59
也就是说,十进制 数字
59
59
59 代表着 状态
B
A
B
C
BABC
BABC
如何把一个十进制数字转换成状态?
例如 数字
59
59
59
第一位为
59
/
(
3
3
)
%
3
=
2
=
>
C
59/(3^3)\%3=2=>C
59/(33)%3=2=>C
第二位为
59
/
(
3
2
)
%
3
=
0
=
>
A
59/(3^2)\%3=0=>A
59/(32)%3=0=>A
第三位为
59
/
(
3
1
)
%
3
=
1
=
>
B
59/(3^1)\%3=1=>B
59/(31)%3=1=>B
第四位为
59
/
(
3
0
)
%
3
=
2
=
>
C
59/(3^0)\%3=2=>C
59/(30)%3=2=>C
得到 状态
B
A
B
C
BABC
BABC
#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int MAXN=6e4+5;
int n,k,M;
//dp分为2层,滚动更新
int dp[2][MAXN];
//预处理pow(3,i),用于表示红绿灯状态
//A-0 B-1 C-2
int pow3[12];
//标记某种状态是否出现
int vis[MAXN];
//保存可能出现的状态
vector<int>saved;
void solve(){
cin>>n>>k>>M;
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
saved.clear();
string s[n+2];
for(int i=1;i<=n;i++){
cin>>s[i];
}
int layer=0;
dp[0][0]=1;
vis[0]=1;
saved.push_back(0);
for(int i=1;i<=n;i++){
for(auto x:saved){
dp[layer^1][x]=dp[layer][x];
}
vector<int>wait;
for(auto x:saved){
int bef=x;
int aft=x;
for(int j=0;j<s[i].length();j++){
//取出从左向右第j+1位
int c=x/pow3[s[i].length()-j-1]%3;
if(s[i][j]=='+'){
aft-=c*pow3[s[i].length()-j-1];
c++; c%=3;
aft+=c*pow3[s[i].length()-j-1];
}else if(s[i][j]=='-'){
aft-=c*pow3[s[i].length()-j-1];
c+=2; c%=3;
aft+=c*pow3[s[i].length()-j-1];
}
}
if(!vis[aft]){
vis[aft]=1;
wait.push_back(aft);
}
dp[layer^1][aft]+=dp[layer][bef];
dp[layer^1][aft]%=M;
}
for(auto x:wait){
saved.push_back(x);
}
layer^=1;
}
sort(saved.begin(),saved.end());
for(auto x:saved){
for(int j=0;j<k;j++){
int c=x/pow3[k-j-1]%3;
if(c==0) cout<<'A';
if(c==1) cout<<'B';
if(c==2) cout<<'C';
}
cout<<' '<<dp[layer][x]<<endl;
}
}
int main(){
// ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
// freopen("./1005.in","r",stdin);
// freopen("./1005.out","w",stdout);
pow3[0]=1;
for(int i=1;i<=11;i++){
pow3[i]=pow3[i-1]*3;
}
int T;cin>>T;
while(T--){
solve();
}
}
这道题一个坑,不能开long long,开了long long会T。