P1049送给圣诞夜的礼品(矩阵十大问题之四)

https://vijos.org/p/1049

P1049送给圣诞夜的礼品

Accepted

标签:组合数学送给圣诞夜的礼物[显示标签]

返回代码界面 | 关闭

Pascal

  • Pascal
  • C
  • C++
  • Python 2.x
  • Java

取消 | 清空代码

描述

当小精灵们把贺卡都书写好了之后。礼品准备部的小精灵们已经把所有的礼品都制作好了。可是由于精神消耗的缘故,他们所做的礼品的质量越来越小,也就是说越来越不让圣诞老人很满意。可是这又是没有办法的事情。

于是圣诞老人把礼品准备部的小精灵们聚集起来,说明了自己的看法:“现在你们有n个礼品,其质量也就是降序排列的。那么为了使得这个礼品序列保持平均,不像现在这样很有规律的降序,我这里有一个列表。”
“列表共有m行,这m行都称作操作(不是序列),每一行有n个数字,这些数字互不相同而且每个数字都在1到n之间。一开始,礼品的序列就是现在礼品所处的位置,也就是说,一开始礼品的序列就是1、2、3、4……n;那么然后,我们看列表的第一行操作,设这一行操作的第i个数字为a[i],那么就把原来序列中的第a[i]个礼物放到现在这个序列的第i的位置上,然后组成新的礼物序列。然后,看列表的第二行操作……、第三行操作……一直到最后一行操作,重复上面的操作。当最后一行的操作结束,组成了的序列又按照第一行来操作,然后第二行操作……第三行操作……一直循环下去,直到一共操作了k行为止。最后生成的这个序列就是我们最终礼品送给孩子们的序列了。大家明白了吗?”
“明白了!”
等圣诞老人一个微笑走后,大家却开始忙碌了。因为m值可能很大很大,而小精灵们的操作速度有限。所以可能在圣诞老人去送礼物之前完成不了这个任务。让他们很是恼火……

格式

输入格式

第一行三个数,n,m和k。

接下来m行,每行n个数。

输出格式

一行,一共n个数,表示最终的礼品序列。n个数之间用一个空格隔开,行尾没有空格,需要回车。

样例1

样例输入1[复制]

7 5 8
6 1 3 7 5 2 4
3 2 4 5 6 7 1
7 1 3 4 5 2 6
5 6 7 3 1 2 4
2 7 3 4 6 1 5

样例输出1[复制]

2 4 6 3 5 1 7

题意:初始数列为1.2.3...n;然后给了m个操作,每个操作都有n个数,表示把第a[i]的数放到第i位置上了,题目让求经过k次操作后的数列分析:后的序列。m<=10, k<2^31。
    首先将这m个置换“合并”起来(算出这m个置换的乘积),然后接下来我们需要执行这个置换k/m次(取整,若有余数则剩下几步模拟即可)。注意任意一个置换都可以表示成矩阵的形式。例如,将1 2 3 4置换为3 1 2 4,相当于下面的矩阵乘法:(第i行第a[i] 为1;因为要把第a[i]个数放到第i个位置)
     


    置换k/m次就相当于在前面乘以k/m个这样的矩阵。我们可以二分计算出该矩阵的k/m次方,再乘以初始序列即可。做出来了别忙着高兴,得意之时就是你灭亡之日,别忘了最后可能还有几个置换需要模拟。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cstdio>
 5 using namespace std;
 6 struct Mat
 7 {
 8     int mat[110][110];
 9 };
10 Mat p[15];
11 int n,m,k;
12 Mat operator * (Mat x, Mat y)
13 {
14     Mat c;
15     memset(c.mat, 0, sizeof(c.mat));
16     for(int t = 1; t <= n; t++)
17     {
18         for(int i = 1; i <= n; i++)
19         {
20             for(int j = 1; j <= n; j++)
21                 c.mat[i][j] += x.mat[i][t] * y.mat[t][j];
22         }
23     }
24     return c;
25 }
26 Mat operator ^ (Mat x, int t)
27 {
28     Mat c;
29     for(int i = 1; i <= n; i++)
30         for(int j = 1; j <= n; j++)
31             c.mat[i][j] = (i == j);
32     while(t)
33     {
34         if(t & 1)
35             c = c * x;
36         x = x * x;
37         t >>= 1;
38     }
39     return c;
40 }
41 int main()
42 {
43     while(scanf("%d%d%d", &n,&m,&k) != EOF)
44     {
45         Mat res,c,a;
46         for(int i = 1; i <= n; i++)
47             a.mat[i][1] = i;
48
49         for(int i = 1; i <= n; i++)
50             for(int j = 1; j <= n; j++)
51                 res.mat[i][j] = (i == j);
52
53         for(int i = 1; i <= m; i++)
54         {
55             memset(c.mat, 0, sizeof(c.mat));
56             for(int j = 1; j <= n; j++)
57             {
58                 scanf("%d", &p[i].mat[j][1]);
59                 c.mat[j][ p[i].mat[j][1] ] = 1;
60             }
61             res = c * res;
62         }
63
64         res = res ^ (k / m);
65         a = res * a;
66         int temp = k % m;
67         for(int i = 1; i <= temp; i++)
68         {
69             memset(c.mat, 0, sizeof(c.mat));
70             for(int j = 1; j <= n; j++)
71                 c.mat[j][ p[i].mat[j][1] ] = 1;
72             a = c * a;
73         }
74         for(int i = 1; i < n; i++)
75         {
76            printf("%d ",a.mat[i][1]);
77         }
78         printf("%d\n",a.mat[n][1]);
79
80     }
81     return 0;
82 }


时间: 2024-08-03 08:00:17

P1049送给圣诞夜的礼品(矩阵十大问题之四)的相关文章

矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

https://vijos.org/p/1049 给出一个序列,含n个数.然后是m个置换,求对初始序列依次进行k次置换,求最后的序列. 先看一个置换,把置换表示成矩阵的形式,然后将m个置换乘起来.那么初始序列首先执行这个置换k/m次,然后顺次执行前k%m个置换,最后乘上初始矩阵. 最后注意矩阵乘法的顺序,A*B != B*A. #include <stdio.h> #include <iostream> #include <map> #include <set&g

送给圣诞夜的礼品

描述 当小精灵们把贺卡都书写好了之后.礼品准备部的小精灵们已经把所有的礼品都制作好了.可是由于精神消耗的缘故,他们所做的礼品的质量越来越小,也就是说越来越不让圣诞老人很满意.可是这又是没有办法的事情. 于是圣诞老人把礼品准备部的小精灵们聚集起来,说明了自己的看法:"现在你们有n个礼品,其质量也就是降序排列的.那么为了使得这个礼品序列保持平均,不像现在这样很有规律的降序,我这里有一个列表." "列表共有m行,这m行都称作操作(不是序列),每一行有n个数字,这些数字互不相同而且每

vijosP1049 送给圣诞夜的礼品

链接:https://vijos.org/p/1049 [思路] 快速幂+矩阵转换. 将m次矩阵的转换看作是一次快速幂中的乘法操作,这样可以用O(log(k/m))的时间求出矩阵进行k/m次操作后的结果,然后把剩下的k%m次矩阵转换补上即可. [代码] 1 #include<iostream> 2 #include<cstring> 3 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 4 using namespace std; 5

[vijos]1051送给圣诞夜的极光&lt;BFS&gt;

送给圣诞夜的极光 题目链接:https://www.vijos.org/p/1051 这是一道很水很水的宽搜水题,我主要是觉得自己在搜素这一块有点生疏于是随便找了一题练手,找到这么一道水题,原本以为可以一次过的,但是状况百出,我并不是很擅长bfs,我以前一直用的Pascal写bfs,但是Pascal没有队列,所以没有c++方便,所以这题我就直接用队列做了,然后完美的炸空间炸时间,后来改成递归调用才通过 思路:这一道题和一道宽搜入门题很像,基本上是一样的,这道题叫细胞个数 链接:http://co

【VIJOS】p1051 送给圣诞夜的极光

描述 圣诞老人回到了北极圣诞区,已经快到12点了.也就是说极光表演要开始了.这里的极光不是极地特有的自然极光景象.而是圣诞老人主持的人造极光. 轰隆隆……烟花响起(来自中国的浏阳花炮之乡).接下来就是极光表演了. 人造极光其实就是空中的一幅幅n*m的点阵图像.只是因为特别明亮而吸引了很多很多小精灵的目光,也成为了圣诞夜最美丽的一刻. 然而在每幅n*m的点阵图像中,每一个点只有发光和不发光两种状态.对于所有的发光的点,在空中就形成了美丽的图画.而这个图画是以若干个(s个)图案组成的.对于图案,圣诞

洛谷 P1454 圣诞夜的极光 == codevs 1293 送给圣诞夜的极光

题目背景 圣诞夜系列~~ 题目描述 圣诞老人回到了北极圣诞区,已经快到12点了.也就是说极光表演要开始了.这里的极光不是极地特有的自然极光景象.而是圣诞老人主持的人造极光. 轰隆隆……烟花响起(来自中国的浏阳花炮之乡).接下来就是极光表演了. 人造极光其实就是空中的一幅幅n*m的点阵图像.只是因为特别明亮而吸引了很多很多小精灵的目光,也成为了圣诞夜最美丽的一刻. 然而在每幅n*m的点阵图像中,每一个点只有发光和不发光两种状态.对于所有的发光的点,在空中就形成了美丽的图画.而这个图画是以若干个(s

【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&amp;混合操作合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.  文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/164.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文算是固定功能Shader的最后一篇,下一次更新应该就会开始讲解表面Shader,而

矩阵十题【三】 HDU 1588 Gauss Fibonacci

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1588 题目大意:先要知道一组斐波那契数列 i 0 1 2 3 4 5 6 7 f(i) 0 1 1 2 3 5 8 13 下面给你一组数: k,b,n,M 现在知道一组公式g(i)=k*i+b:(i=0,1,2,3...n-1) 让你求出 f(g(i)) 的总和(i=01,2,3,...,n-1),比如给出的数据是2 1 4 100 2*0+1=1   f(1)=1 2*1+1=3   f(3)=2

矩阵十题【一】

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=298 题目大意:已知n个点(n<10000),现在对所有点进行以下操作: 平移一定距离(M),相对X轴上下翻转(X),相对Y轴左右翻转(Y),坐标缩小或放大一定的倍数(S),所有点对坐标原点逆时针旋转一定角度(R). 操作的次数不超过1000000次,求最终所有点的坐标. 首先我们要知道矩阵乘法的概念. 在数学中,一个矩阵说穿了就是一个二维数组.一个n行m列的矩阵可以乘以一个m行p列的矩