1005-交通管控-2024“钉耙编程”中国大学生算法设计超级联赛(6)

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 233+032+131+230=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。
在这里插入图片描述

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值