H - XXX的机器人

Time Limit: 6000/3000MS (Java/Others) Memory Limit: 65536/32768KB (Java/Others)
SubmitStatus

Problem Description

XX手里有5张卡片,卡片上的数字分别是1~5的某个全排列a[l], a[2], a[3], a[4], a[5](比如2 3 1 5 4)。

有n个房间。每个房间都有一个卡片转化规则,每个规则也是1~5的某个全排列b[l], b[2], b[3], b[4], b[5](比如 3 4 2 1 5)。

每进入到一个房间手里的卡片会根据当前房间的规则做相应的变换:a[i] = b[ a[i] ] (1 <= i <= 5)。

相邻的两个房间是相连的,也就是说第i个房间可以走到i+1房间和i-1房间(如果i+1房间和i-1房间存在的话)。

XX的目标是使手里的卡片变成1 2 3 4 5。

由于XX要和奶茶妹妹约会,没有时间,所有他派遣一个机器人去帮他。并且写了m条指令。

每一条指令的格式是S T, 表示从S房间走到T房间。

这m条指令只能按顺序执行。对于每条指令机器人可以选择执行或不执行。

这个机器人想知道最少要路过多少个房间可以达到XX的要求。

Input

输入有多组数据,对于每组数据:
      第一行为两个数字n, m(2<=n<=100000,  0<= m <= 100),表示有n个房间,有m条指令。

接下来有n行,每行5个数字(为1~5的某个全排列),表示每一个房间的转换规则。

然后有m行,每一行有两个数字S, T( 1<=S, T<=n, S != T)表示每条指令。

最后一行有5个数字(为1~5的某个全排列),表示XX初始时手里的卡片。

Output

对于每组数据,输出最小值。如果没有满足条件的最小值,那么输出-1。

Sample Input

2 2
1 5 2 3 4
1 3 5 2 4
2 1
2 1
1 2 4 5 3

Sample Output

4

Hint

只有这两条指令都执行才能达到要求,所以要路过4个房间

H题

Dp[i][j]表示执行了i指令之后状态为j的 路过最小房间数。 j可以用康托展开把全排列hash为一个数字。

置换群满足结合律,可以用两棵线段树维护分别维护正向与反向的指令。

方法一:可以用线段树计算出指令.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 111111;
const int inf = 0x7f7f7f7f;
//=====================================================
/*
inline int scanf(int &num)
{
    char in;
    bool neg=false;
    while((in=getchar())!=EOF && (in>'9' || in<'0') && in!='-');
    if(in==EOF) return 0;
    else if(in=='-') neg=true,num=0;
    else  num=in-'0';
    while(in=getchar(),in>='0' && in<='9') num*=10,num+=in-'0';
    if(neg) num=-num;
    return 1;
}
*/
//======================================================
int h[] = {0, 24, 6, 2, 1, 1};
struct node {
    int a[6];
    node() {
        for(int i = 1; i <= 5; i++) {
            a[i] = i;
        }
    }
    node(int tp[]) {
        for(int i = 1; i <= 5; i++) {
            a[i] = tp[i];
        }
    }
    node(int val) {
        int sta = 0;
        for(int i = 1; i <= 5; i++) {
            int k = val / h[i];
            val %= h[i];
            int cnt = 0;
            for(int j = 1; j <= 5; j++) {
                if( (sta & (1 << j)) == 0 ) {
                    if(cnt == k) {
                        sta |= (1 << j);
                        a[i] = j;
                        break;
                    }
                    else {
                        cnt++;
                    }
                }
            }
        }
    }
    node operator * (const node &tp) const {
        node ret;
        for(int i = 1; i <= 5; i++) {
            ret.a[i] = tp.a[ a[i] ];
        }
        return ret;
    }
    node operator = (const node &tp) {
        for(int i = 1; i <= 5; i++) {
            a[i] = tp.a[i];
        }
        return (*this);
    }
    void show() {
        for(int i = 1; i <= 5; i++) {
            if(i != 1) cout << ' ';
            cout << a[i];
        }
        cout << endl;
    }
    void input() {
        for(int i = 1; i <= 5; i++) {
            scanf("%d", a + i);
            //scanf(a[i]);
        }
    }
};
node room[maxn];
struct SegTree {
    node num[maxn << 2];
    bool flag;
    void build(int l, int r, int rt) {
        if(l == r) {
            num[rt] = room[l];
            return;
        }
        int m = (l + r) >> 1;
        if(flag) {
            build(lson);
            build(rson);
            num[rt] = num[rt << 1] * num[rt << 1 | 1];
        }
        else {
            build(rson);
            build(lson);
            num[rt] = num[rt << 1 | 1] * num[rt << 1];
        }
    }
    node query(int ll, int rr, int l, int r, int rt) {
        if(ll <= l && r <= rr) {
            return num[rt];
        }
        int m = (l + r) >> 1;
        node ret;
        if(flag) {
            if(ll <= m) ret = ret * query(ll, rr, lson);
            if(rr > m) ret = ret * query(ll, rr, rson);
        }
        else {
            if(rr > m) ret = ret * query(ll, rr, rson);
            if(ll <= m) ret = ret * query(ll, rr, lson);
        }
        return ret;
    }
}tree[2];
int get_hash(int num[]) {
    int ret = 0;
    for(int i = 1; i <= 5; i++) {
        int cnt = 0;
        for(int j = i + 1; j <= 5; j++) {
            if(num[i] > num[j]) {
                cnt++;
            }
        }
        ret += cnt * h[i];
    }
    return ret;
}
int dp[111][133];
node op[111];
node start;
int cnt[111];
int main() {
//    freopen("robot.in", "r", stdin);
//    freopen("robot.out", "w", stdout);
    int n, m;
    while(~scanf("%d %d", &n, &m)) {
        for(int i = 1; i <= n; i++) {
            room[i].input();
        }
        tree[0].flag = 0;
        tree[1].flag = 1;
        tree[0].build(1, n, 1);
        tree[1].build(1, n, 1);
        for(int i = 1; i <= m; i++) {
            int l, r;
            scanf("%d%d", &l, &r);
            //scanf(l); scanf(r);
            op[i] = tree[l < r].query(min(l, r), max(l, r), 1, n, 1);
            cnt[i] = max(l, r) - min(l, r) + 1;
        }
        start.input();
        memset(dp, 0x7f, sizeof(dp));
        dp[0][ get_hash(start.a) ] = 0;
        for(int i = 1; i <= m; i++) {
            for(int j=0;j<120;j++) dp[i][j]=dp[i-1][j];
            for(int j = 0; j < 120; j++) {
                if(dp[i-1][j] == inf) continue;
                node now(j);
                node next = now * op[i];
                int sta = get_hash(next.a);
                dp[i][sta] = min(dp[i][sta], dp[i-1][j] + cnt[i]);
            }
        }
        if(dp[m][0] == inf) dp[m][0] = -1;
        printf("%d\n", dp[m][0]);
    }
    return 0;
}

方法二: 也可以计算出前后缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=100005;
const int mod=1007;
const double eps=1e-8;
const int inf=(1<<30);
//-----------------------------------------------------------------------------
int from[3333]; //编号i对应的排列为from[i]
int to[3333];  //排列i对应的编号为to[i]
int HASH(int b[]) { //五进制压缩
    int x=0;
    for(int i=0;i<5;i++) x=x*5+(b[i]-1);
    return x;
}
void getnum() { //对12345所有的排列进行编号映射
    int idx=0;
    int b[]={1,2,3,4,5};
    do {
        int x=0;
        for(int i=0;i<5;i++) x=x*5+(b[i]-1);
        from[++idx]=x; //编号idx对应排列为x
        to[x]=idx; //排列x对应编号为idx
    }while(next_permutation(b,b+5));
}
int tran(int x,int y) { //x通过置换规则y变成ret
    int i,A[6],B[6];
    for(i=4;i>=0;x/=5,i--) A[i]=x%5;
    for(i=4;i>=0;y/=5,i--) B[i]=y%5;
    int ret=0;
    for(i=0;i<5;i++) ret=ret*5+B[A[i]];
    return ret;
}
int tran2(int x,int y) { //x由置换规则ret变成y
    int i,A[6],B[6],C[6];
    for(i=4;i>=0;x/=5,i--) A[i]=x%5;
    for(i=4;i>=0;y/=5,i--) B[i]=y%5;
    for(i=0;i<5;i++) C[A[i]]=B[i];
    int ret=0;
    for(i=0;i<5;i++) ret=ret*5+C[i];
    return ret;
}
void out(int x) {
    printf("```: ");
    int i,A[6];
    for(i=4;i>=0;x/=5,i--) A[i]=x%5;
    for(i=0;i<5;i++) printf("%d ",A[i]+1);
    puts("");
}
int n,m;
int a[N]; //每个房间的置换规则
int tl[N],tr[N]; //置换前缀,置换后缀
int tb[111],cnt[111]; //每个操作对应置换规则; 走过的房间数
int dp[111][122]; //dp[i][j] 前i个操作置换为排列j的最小房间数
int main()
{
//    freopen("robot.in","r",stdin);
//    freopen("out2.txt","w",stdout);
    int i,j,t,cas=0;
    int S,T;
    int b[6];
    getnum();
    while(scanf("%d%d",&n,&m)!=EOF) {
        memset(dp,-1,sizeof(dp));
        for(i=0;i<5;i++) b[i]=i+1;
        tl[0]=tr[n+1]=a[0]=HASH(b);
        for(i=1;i<=n;i++) {
            for(j=0;j<5;j++) scanf("%d",&b[j]);
            a[i]=HASH(b);
        }
        for(i=1;i<=n;i++) tl[i]=tran(tl[i-1],a[i]);
        for(i=n;i>=1;i--) tr[i]=tran(tr[i+1],a[i]);
        for(i=1;i<=m;i++) {
            scanf("%d%d",&S,&T);
            if(S<T) {
                tb[i]=tran2(tl[S-1],tl[T]);
                cnt[i]=T-S+1;
            }else {
                tb[i]=tran2(tr[S+1],tr[T]);
                cnt[i]=S-T+1;
            }
        }
        for(i=0;i<5;i++) scanf("%d",&b[i]);
        int x=HASH(b);
        dp[0][to[x]]=0;
        for(i=1;i<=m;i++) {
            for(j=1;j<=120;j++) dp[i][j]=dp[i-1][j];
            for(j=1;j<=120;j++) {
                if(dp[i-1][j]==-1) continue;
                int c=tran(from[j],tb[i]);
                int z=to[c];
                if(dp[i][z]==-1||dp[i][z]>dp[i-1][j]+cnt[i])
                    dp[i][z]=dp[i-1][j]+cnt[i];
            }
        }
        printf("%d\n",dp[m][ to[ a[0] ] ]);
    }
    return 0;
}

ACdream原创群赛(11)の风神日华神专场 H - XXX的机器人相关推荐

  1. ACdream原创群赛(11)の风神日华神专场 G - 风之国

    G - 风之国 Time Limit: 6000/3000MS (Java/Others) Memory Limit: 65536/32768KB (Java/Others) SubmitStatus ...

  2. ACdream原创群赛(11)の风神日华神专场 C.神奇的%系列一

    神奇的%系列一 Time Limit: 6000/3000 MS (Java/Others)     Memory Limit: 65536/32768 KB (Java/Others) Proble ...

  3. ACdream原创群赛(18)のAK's dream

    ACdream原创群赛(18)のAK's dream 题目链接 A:水题,直接模拟题意去搞即可 D:贪心+组合数学,把剑和英雄都从小到大排序,每次计算该英雄能用前几把剑cnt,cnt减去之前有多少人就 ...

  4. dp --- acdream原创群赛(16) --- B - Apple

    <传送门> B - Apple Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Other ...

  5. 如何利用大数据做金融风控? 原创 2016年11月24日 17:42:03 标签: 大数据 / 金融 / 风控 1594 导语:如何通过海量数据与欺诈风险进行博弈? 随着金融科技、科技金融等概念的

    如何利用大数据做金融风控? 原创 2016年11月24日 17:42:03 标签: 大数据 / 金融 / 风控 1594 导语:如何通过海量数据与欺诈风险进行博弈? 随着金融科技.科技金融等概念的热起 ...

  6. The Wide and Deep Learning Model(译文+Tensorlfow源码解析) 原创 2017年11月03日 22:14:47 标签: 深度学习 / 谷歌 / tensorf

    The Wide and Deep Learning Model(译文+Tensorlfow源码解析) 原创 2017年11月03日 22:14:47 标签: 深度学习 / 谷歌 / tensorfl ...

  7. 群赛 round#8 解题报告一 (swop,ranwen,easy)

    群赛 round#8 解题报告一 赛制: OI 难度: noip T1 交换!交换!(swop) [问题描述] ljm喜欢交换物品,他觉得这样可以与更多人分享好的事物. 有一天,lzx给了ljm n本 ...

  8. 备战Noip2018模拟赛11(B组)T4 Path 好路线

    10月27日备战Noip2018模拟赛11(B组) T4路径好路线 题目描述 nodgd在旅游.现在,nodgd要从城市的西北角走到东南角去.这个城市的道路并不平坦,nodgd希望找出一条相对比较好走 ...

  9. 神码ai人工智能写作机器人_从云到设备到边缘的人工智能和机器学习的未来

    神码ai人工智能写作机器人 A brief overview of the state-of-the-art in training ML models on devices. For a more ...

最新文章

  1. iis下 ActiveSync插件无法访问(下)
  2. 实战NFS服务搭建与配置
  3. Mysql 8 group replication组复制集群单主配置图解
  4. RabbitMQ/pika模块
  5. 电脑键盘功能介绍_Excel应用041:全能电脑抽奖神器(功能介绍)(原创作品) ?...
  6. 图的m着色问题(洛谷-P2819)
  7. javaweb实训第一天上午——HTML和CSS
  8. ros melodic控制真实机械臂之moveit_setup_assistant配置
  9. react中创建组件
  10. linux下qt网络编程 qnetworkreply,QT网络编程之文件下载 QNetworkRequest QNetworkReply QNetworkAccessManager...
  11. 工作效率的提升——如何高效沟通,有效降低沟通成本
  12. 金属,还是Disturbed的好。
  13. VsCode常用插件和快捷键
  14. 解读7种水质对咖啡口感的影响
  15. 什么是软件验收测试?如何获取软件验收测试报告
  16. mysql中TINYINT的取值范围
  17. atto软件测试速度,评测平台介绍及HD Tune、ATTO性能测试
  18. Ubuntu 22 安装gcc7 g++7
  19. 如何求两个文件的交集、并集和差集?------sort和uniq闪亮登场
  20. 【Python入门教程】教你如何10分钟入门Python!(超详细)

热门文章

  1. python:编解码器基类之无状态的编码和解码
  2. Java基于JSP校园二手闲置商品交易系统
  3. Windows Tomcat 下载安装
  4. android打电话 接电话 挂电话流程分析
  5. 金蝶EAS BOS合并报表取数公式(二次开发取数公式)在调整分录模板和抵消分录模板显示
  6. VBO转HDMI OUT 支持常用分辨率,最大支持4K60HZ
  7. Linux的远程终端连不上,Linux系统远程连接终端连接不上怎么办
  8. ERPS环网络端口角色
  9. 仙侠手游源码《一剑问情》完整云服务器搭建过程-源码带GM后台+视频教程加文字教程
  10. db2 迁移 aix linux,DB2从windowsXP迁移至AIX完整过程