2024杭电多校06——1005交通管控

补题点这里

在这里插入图片描述

大意 一个操作杆可以对k个红绿灯进行操作,操作杆上的一个字符对应一个红绿灯,操作包括+,-,0,问每种组合方案有多少种组合方式
+: red->green->yellow->red
-:green->red->yellow->green

可以用一个三进制数表示每个灯的状态,因为k最多只有10个, 3 10 ≤ 60000 3^{10}\leq 60000 31060000, 仔细看会发现+,-操作一个是顺时针转一圈,一个是逆时针转一圈,用 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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值