补题点这里
大意 一个操作杆可以对k个红绿灯进行操作,操作杆上的一个字符对应一个红绿灯,操作包括+,-,0,问每种组合方案有多少种组合方式
+: red->green->yellow->red
-:green->red->yellow->green
可以用一个三进制数表示每个灯的状态,因为k最多只有10个,
3
10
≤
60000
3^{10}\leq 60000
310≤60000, 仔细看会发现+,-操作一个是顺时针转一圈,一个是逆时针转一圈,用
0
,
1
,
2
0,1,2
0,1,2分别表示绿色,黄色,和红色,那么其实就相当于加一再模3,和减一再模三的操作.
每个操作杆用或不用可以考虑类似01背包的动态规划.
设f[i]表示i这个状态有多少种方案
f
[
i
]
=
(
f
[
j
]
+
f
[
i
]
)
%
m
o
d
f[i] = (f[j] +f[i]) \% mod
f[i]=(f[j]+f[i])%mod 其中
i
i
i是j经过操作杆
x
x
x变化而来的, 所以其实本来的方程有二维,表示的是用到第几个操作杆,但是这一维可以不要,我没有开滚动数组,是另一种常见优化,存储上一轮的结果,用上一轮的结果进行转移,时间复杂度大概是
O
(
n
k
3
k
)
O(nk3^{k})
O(nk3k) 最多
3
e
8
3e8
3e8次,开了
10
s
10s
10s可以接受
最后输出答案的话,我写了个 v e c t o r < p a i r < s t r i n g , i n t > > vector<pair<string,int>> vector<pair<string,int>>,sort了一下,不知道有没有更快的方法,有的话告诉我一下
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using i64 = long long;
i64 square3[100];
i64 n,k,mod;
//绿色是0,红色是2,黄色是1
inline void solve(){
cin>>n>>k>>mod;
vector<string> op(n+1);
for(int i = 1;i<=n;++i) cin>>op[i];
vector<i64> f(square3[k]+1,0),f1;//f[i]:i这个状态有多少种方案
vector<bool> vis(square3[k]+1,0),vis1;
f[0]=1LL;
vis[0]=1;
for(int i = 1;i<=n;++i){
f1 = f;
vis1 = vis;
//x x x x x x Base3
//0 1 2 3 4 k-1 遍历顺序,操作顺序
//k-1 k-2 ...0 位次
for(int j = 0;j<square3[k];++j){
if(vis1[j]==0) continue;
int tmp=0;
for(int s = 0;s<k;++s){
int t = (j/square3[k-1-s])%3;
if(op[i][s]=='+') (t+=1)%=3;
else if(op[i][s]=='-') (t+=2)%=3;
tmp = tmp*3+t;
}
f[tmp] = (f[tmp]+f1[j])%mod;
vis[tmp]=1;
}
}
vector<pair<string,int>>p;
//map<string,int> mp;应该也能过
for(int i = 0;i<square3[k];++i){
if(!vis[i]) continue;
string ss;
for(int j = k-1;j>=0;--j){
int t = (i/square3[j])%3;
ss+=char('A'+t);
}
p.push_back({ss,f[i]%mod});
//mp[ss] = f[i]%mod;
}
sort(p.begin(),p.end());
for(auto i:p){
cout<<i.first<<" "<<i.second%mod<<"\n";
}
}
signed main(){
ios;
square3[0]=1LL;
for(int i =1;i<=15;++i) square3[i] = square3[i-1]*3LL;
int t;cin>>t;
while(t--){
solve();
}
return 0;
}
写代码途中遇到的问题,TLE,vector直接开60000就会T,要根据k来开,想要更快的话其实可以再读入的时候就开始操作(看std学的).取某一位三进制,进位退位这种操作有比较简单的写法,(写一堆内联函数就显得有点愚蠢->me)