HDU4887_Endless Punishment_BSGS+矩阵快速幂+哈希表
2014多校第一题,当时几百个人交没人过,我也暴力交了几发,果然不行。
比完了去学习了BSGS才懂!
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4887
Endless PunishmentTime Limit: 30000/15000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 52 Accepted Submission(s): 24 Problem Description
In the ancient Greek tale, Sisyphus was a king of Ephyra, he was punished for chronic deceitfulness by being compelled to roll an immense stone up a hill every day, only to watch it roll back down, and to repeat this action forever.
Zeus, the God of the universe, shows some mercy for Sisyphus, so he decides to change the way of punishment. He puts N stones with the color of white or black in a line on the hill, everyday when Sisyphus rolls a new stone up the hill, the new stone is added to the back of the old N stones, and the first stone rolls down to the foot of the hill. Then Zeus shows his magic to change the color of the new N stones. Firstly, he looks at a subset S1 of the original N stones, which always includes the first stone, if an odd number of the stones are black, then the newly N-th stone will be black and white otherwise. After the first step is done, he flips the color of another subset S2 of the new N stones, black stone will become white, and white stone will become black vice versa. The following example illustrates how Zeus's magic works. Consider the case of N = 4, S1 = {1,3}, S2 = {2,4}. Suppose the current stone color state is ●○○○, (○ for white stone, and ● for black stone), the 1st and 3rd stone is black and white respectively, so the new 4th stone will be black, produces ○○○● after the first step. At the second step, the 2nd and 4th stone flip its color, produces ○●○○ in the end. Zeus tells to Sisyphus that, if one day after the two steps are done, the color of the stones turns to one specific state, he will get his freedom. Now given the current and final stone colors, please compute how many days are needed for Sisyphus's freedom? Input
There are several test cases, please process till EOF.
For each test case, the first line contains three integers, the first integer is N(2 ≤ N ≤ 31), the number of stones, followed by two integers S1 and S2, (1 ≤ S1,S2 ≤ N), denoting the size of two subsets as mentioned above. The second and third line contains S1 and S2 integers a and b in the increasing order, describing the two subsets. It is guaranteed that a1 always equals to 1. The last two lines each contains N integers with 0 (for white), or 1 (for black) denoting the current and final state. The first integer describes the first stone, and the last integer describes the last stone. Please note that there are about 500 test cases, fortunately, only 20 of them are big test cases. Output
For each test case, output a single integer, the minimum days for Sisyphus to get his freedom. If Zeus is an absolute liar, then just simply print the sentence poor sisyphus.
Sample Input
4 2 2
1 3 2 4 1 0 0 0 0 1 0 0 4 2 2 1 3 2 4 1 1 1 1 0 0 0 0 4 2 2 1 3 2 4 1 1 1 1 0 1 0 0 10 5 6 1 2 4 5 6 2 4 5 8 9 10 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 Sample Output
1
4 poor sisyphus 387 Author
Fudan University
Source
|
题目大意:
宙斯要一个叫西西斯斯的人搬石头,石头在山上排成一排,最多31个,按当前称为第一个、第二个、……第31个。宙斯每天把第一个石头踢下来,全部往前移一位,让西西比斯带一个新的放在第31个的位置。石头都有两种颜色黑和白,初始颜色序列和最终颜色序列给定了。
宙斯还给了2个集合,A和B,存的是若干个位置。每次宙斯要踢石头下去之前,先算一下集合A包含的那些石头有多少个黑的,要是有奇数个黑的,就把新搬上来的时候刷成黑色,否则是白色。集合A必包含第一个位置。
然后踢下去搬上来结束后,宙斯把集合B的石头都刷成反色。
每天就这2个操作,给了石头数N,集合A、集合B,起始颜色序列,最终颜色序列,求多少天能到最终颜色序列。
题解:
BSGS+矩阵快速幂+哈希表。
用一维bool向量代表一组石头排列,加一位后就能用矩阵乘法来进行那两个操作,因为xor操作和模2的矩阵乘法一模一样。石头位移很容易在矩阵乘法中表示,石头反色就是+1(或者说xor 1),这个反色可以在新的一位中实现(石头序列向量中新的一位总为1,操作矩阵中新的一列需要反色的位置为1,其他为0)。然后再弄一个矩阵来表示新石头的颜色计算操作,就是矩阵中和计算新石头的那一位有关的那一维中,集合A包含的位置为1,其他为0。(注意A包含的是踢前的位置,B包含的是踢后的位置,在生成矩阵时要注意)。然后这两个矩阵乘起来就能得到一天的操作的矩阵。
因为A集合必包含第一个位置,所以被踢下去的时候和新上来的石头的颜色是有关联的,知道一个能算另一个,所以每天的操作能逆推。我们可以弄一个正向操作的矩阵和一个逆向操作的矩阵。(直接根据题意生成,不要乱求什么逆矩阵啊)
上面是基础,下面才是关键,我们要用BSGS来大幅减少运算!
BSGS全称BabySteps GiantSteps,在我的这一篇里面有提到:http://www.cnblogs.com/yuiffy/p/3877381.html
思想是先算m=ceil(sqrt(N))(N为所有可能状态数,在这题里N=1<<n)
然后计算从起始状态开始的前m个状态,(now,i)存入蛤习表里(now为状态,因为状态最多只有1<<31个,可以用数字表示,i为状态序号)。这题最大N=1<<31,sqrt一下只有四万多,非常好存。
上面那个是babysteps,下面这个是giantsteps。(推荐两首歌:Baby Steps-Varsity,Giant Step-Astronauts(May'n・椎名慶治))
把m次逆操作合到一起(在这题里就是用快速幂算出nc=逆矩阵的m次方),然后从终点状态开始,一次走m步(在这题里是乘上那个nc)。
因为开头连续的m个已经算好,我一次走m步,只要踏进我算好的那m个中,就得到了答案!时间复杂度直接开了个方,我都怕!
优化:
1.用unsigned int就行,不需要long long。
2.babysteps的时候可以直接位运算,不用矩阵乘法,快一点。
另外:
VC++编译器能用hash_map代替手写哈希,特别碉炸,附上代码在下下面。
手写哈希版的代码:
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll __int64
#define usint unsigned int
#define RE freopen("1.in","r",stdin)
const usint NONE=0xffffffff; int n,s1,s2;
int a1[],a2[];
usint xo; class hash {
public:
hash() {
memset(a,0xff,sizeof(a));
}
usint locate(usint x) {
usint l=x%MOD;
while(a[l]!=x&&a[l]!=NONE) l=l+;
return l;
}
void insert(usint x,usint va) {
usint l=locate(x);
if(a[l]==NONE) {
a[l]=x;
v[l]=va;
}
}
usint get(usint x) {
usint l=locate(x);
return a[l]==x?v[l]:NONE;
}
void clear() {
memset(a,0xff,sizeof(a));
}
private:
static const usint MOD=;
usint a[MOD+],v[MOD+];
} S; struct vct {
bool a[];
vct(bool q[]) {
for(int i=; i<=n; i++)
a[i]=q[i];
}
vct() {}
void clear() {
memset(a,,sizeof(a));
}
void show() {
for(int i=; i<=n; i++)
printf("%d ",a[i]);
puts("");
}
};
struct matrix {
bool a[][];
matrix(bool q[][]) {
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
a[i][j]=q[i][j];
}
matrix() {}
void clear() {
memset(a,,sizeof(a));
} friend matrix operator *(matrix A,matrix B) {
matrix re;
int i,j,k;
re.clear();
for(i=; i<=n; i++)
for(j=; j<=n; j++)
for(k=; k<=n; k++)
re.a[i][j]=(re.a[i][j]^(A.a[i][k]*B.a[k][j]));
//re.show();
return re;
}
void danwei() {
memset(a,,sizeof(a));
for(int i=; i<=n; i++)
a[i][i]=;
}
void show() {
for(int i=; i<=n; i++) {
for(int j=; j<=n; j++)
printf("%d ",a[i][j]);
puts("");
}
}
}; inline usint atox(bool a[],int n) {
usint re=;
for(int i=; i<n; i++)
re=(re<<)+a[n-i-];
return re;
} inline int xtoa(bool a[],int n,usint x) {
for(int i=; i<n; i++) {
a[i]=x&;
x=x>>;
}
} void check(bool a[],int n) {
for(int i=; i<n; i++)
printf("%2d",a[i]);
puts("");
} inline usint next(usint now) {
bool a[],j;
usint re;
xtoa(a,n,now);
j=a[a1[]];
for(int i=; i<s1; i++)
j^=a[a1[i]];
re=(now>>)+(j<<(n-));
re^=xo;
return re;
} vct operator * (matrix mt,vct v) {
vct re;
int i,j;
re.clear();
for(i=; i<=n; i++)
for(j=; j<=n; j++)
re.a[i]=(re.a[i]^(mt.a[i][j]*v.a[j]));
return re;
} matrix qpow(matrix a,usint x) {
matrix re,t;
re.danwei();
t=a;
while(x>) {
if(x&==)re=re*t;
x=x>>;
t=t*t;
}
return re;
}
int main() {
usint i,j;
bool a[];
usint cnt;
usint st,ed,now,m,t;
matrix ni,nc,n1,n2;
vct v;
//RE;
while(scanf("%d%d%d",&n,&s1,&s2)!=EOF) {
for(i=; i<s1; i++) {
scanf("%d",&a1[i]);
a1[i]--;
}
xo=;
for(i=; i<s2; i++) {
scanf("%d",&j);
a2[i]=j-;
xo=xo|(<<(j-));
}
for(i=; i<n; i++)
scanf("%d",&a[i]);
st=atox(a,n);
for(i=; i<n; i++)
scanf("%d",&a[i]);
ed=atox(a,n); ///怒求矩阵
n1.clear();
n2.clear();
for(i=; i<=n; i++)
n2.a[i][i]=;
for(i=; i<s2; i++)
n2.a[a2[i]][n]=;
for(i=; i<s1; i++)
if(a1[i]>) n1.a[][a1[i]-]=;
n1.a[][n-]=;
for(i=; i<n-; i++)
n1.a[i+][i]=;
n1.a[n][n]=;
ni=n1*n2; ///怒存开头m个
now=st;
S.clear();
m=ceil(sqrt(((usint))<<n));///不先强转usint的话<<31会变0
for(i=0; i<m; i++) {
S.insert(now,i);
now=next(now);/**One, two, baby steps.Three, four, baby steps.Five, six, baby steps.**/
} nc=qpow(ni,m);///怒算逆m次操作的矩阵 ///怒从结尾往前m个m个地找,怒找有没有开头m个
now=ed;
cnt=;
t=S.get(now);
while(t==NONE) {
if(cnt>m) break;
xtoa(v.a,n,now);
v.a[n]=;
v=nc*v;/**一歩 Giant Step , 君にとってLittle だとしても**/
now=atox(v.a,n);
cnt++;
t=S.get(now);
}
//cout<<m<<','<<cnt<<','<<t<<endl;
if(t==NONE) printf("poor sisyphus\n");
else printf("%u\n",cnt*m+t);
}
return ;
}
hash_map版的代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set> #include<hash_map> #define ll __int64
#define usint unsigned int
#define RE freopen("1.in","r",stdin)
#define mp make_pair using namespace stdext;
using namespace std; int n,s1,s2,a1[],a2[];
usint xo; hash_map<usint,usint>S; struct vct {
bool a[];
inline vct(const bool q[]) {
for(int i=; i<=n; i++)
a[i]=q[i];
}
inline vct() {}
inline void clear() {
memset(a,,sizeof(a));
}
inline void show() {
for(int i=; i<=n; i++)
printf("%d ",a[i]);
puts("");
}
inline void operator =(const bool q[]) {
for(int i=; i<=n; i++)
a[i]=q[i];
}
};
struct matrix {
bool a[][];
inline matrix(const bool q[][]) {
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
a[i][j]=q[i][j];
}
inline matrix() {}
inline void clear() {
memset(a,,sizeof(a));
} inline friend matrix operator *(const matrix &A,const matrix &B) {
matrix re;
int i,j,k;
re.clear();
for(i=; i<=n; i++)
for(j=; j<=n; j++)
for(k=; k<=n; k++)
re.a[i][j]=(re.a[i][j]^(A.a[i][k]&B.a[k][j]));
//re.show();
return re;
}
inline void danwei(){
memset(a,,sizeof(a));
for(int i=;i<=n;i++)
a[i][i]=;
}
inline void show() {
for(int i=; i<=n; i++) {
for(int j=; j<=n; j++)
printf("%d ",a[i][j]);
puts("");
}
}
}; inline usint atox(const bool a[],const int &n) {
usint re=;
for(int i=; i<n; i++)
re=(re<<)+a[n-i-];
return re;
} inline void xtoa(bool a[],const int &n,usint x) {
for(int i=; i<n; i++) {
a[i]=x&;
x=x>>;
}
} inline usint next(const usint &now) {
bool a[],j;
usint re;
xtoa(a,n,now);
j=a[a1[]];
for(int i=; i<s1; i++)
j^=a[a1[i]];
re=(now>>)+(j<<(n-));
re^=xo;
return re;
} inline vct operator * (const matrix &mt,const vct &v) {
vct re;
int i,j;
re.clear();
for(i=; i<=n; i++)
for(j=; j<=n; j++)
re.a[i]=(re.a[i]^(mt.a[i][j]&v.a[j]));
return re;
} inline matrix qpow(const matrix &a,usint x)
{
matrix re,t;
re.danwei();
t=a;
while(x>)
{
if(x&==)re=re*t;
x=x>>;
t=t*t;
}
return re;
}
int main() {
usint i,j,m,t,cnt,st,ed,now;;
matrix n1,n2,ni,nc;
vct v; while(scanf("%d%d%d",&n,&s1,&s2)!=EOF) {
for(i=; i<s1; i++) {
scanf("%d",&a1[i]);
a1[i]--;
}
xo=;
for(i=; i<s2; i++) {
scanf("%d",&a2[i]);
a2[i]--;
xo=xo|(<<a2[i]);
}
for(i=; i<n; i++)
scanf("%d",&v.a[i]);
st=atox(v.a,n);
for(i=; i<n; i++)
scanf("%d",&v.a[i]);
ed=atox(v.a,n); ///怒造矩阵
n1.clear();
n2.clear();
for(i=; i<=n; i++)
n2.a[i][i]=;
for(i=; i<s2; i++)
n2.a[a2[i]][n]=;
for(i=; i<s1; i++)
if(a1[i]>) n1.a[][a1[i]-]=;
n1.a[][n-]=;
for(i=; i<n-; i++)
n1.a[i+][i]=;
n1.a[n][n]=;
ni=n1*n2; ///怒存m个
now=st;
S.clear();
m=ceil(sqrt((double)(((usint))<<n)));
for(i=; i<m; i++) {
S.insert(mp(now,i));
now=next(now);
} nc=qpow(ni,m);
v.a[n]=;
now=ed;
cnt=;
hash_map<usint,usint>::iterator tt=S.find(now);
while(tt==S.end()) {
if(cnt>m)break;
v=nc*v;
now=atox(v.a,n);
cnt++;
tt=S.find(now);
}
if(tt==S.end()) printf("poor sisyphus\n");
else printf("%u\n",cnt*m + tt->second);
}
return ;
}
HDU4887_Endless Punishment_BSGS+矩阵快速幂+哈希表的更多相关文章
- bzoj 4128: Matrix ——BSGS&&矩阵快速幂&&哈希
题目 给定矩阵A, B和模数p,求最小的正整数x满足 A^x = B(mod p). 分析 与整数的离散对数类似,只不过普通乘法换乘了矩阵乘法. 由于矩阵的求逆麻烦,使用 $A^{km-t} = B( ...
- Nowcoder 练习赛 17 C 操作数 ( k次前缀和、矩阵快速幂打表找规律、组合数 )
题目链接 题意 : 给定长度为n的数组a,定义一次操作为: 1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007: 2. ...
- HDU-6030 Happy Necklace 打表+矩阵快速幂
Happy Necklace 前天个人赛规律都找出来了,n的范围是\(10^{18}\),我一想GG,肯定是矩阵快速幂,然后就放弃了. 昨天学了一下矩阵快速幂. 题意 现在小Q要为他的女朋友一个有n个 ...
- hdu 5451 Best Solver 矩阵循环群+矩阵快速幂
http://acm.hdu.edu.cn/showproblem.php?pid=5451 题意:给定x 求解 思路: 由斐波那契数列的两种表示方法, 之后可以转化为 线性表示 F[n] = ...
- hdu 1005 Number Sequence(矩阵快速幂,找规律,模版更通用)
题目 第一次做是看了大牛的找规律结果,如下: //显然我看了答案,循环节点是48,但是为什么是48,据说是高手打表出来的 #include<stdio.h> int main() { ], ...
- [技术]浅谈OI中矩阵快速幂的用法
前言 矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中,矩阵的运算是数值分析领域的重要问题. 基本介绍 (该部分为入门向,非入门选手可以跳过) 由 m行n列元素排列成的矩形阵列.矩阵里的 ...
- HDU1005 找规律 or 循环点 or 矩阵快速幂
http://acm.hdu.edu.cn/showproblem.php?pid=1005 1.一开始就注意到了n的数据范围 <=100 000 000,但是还是用普通的循环做的,自然TLE了 ...
- 【HNOI2002】【矩阵快速幂】公交车路线
仍然是学弟出的题目的原题@lher 学弟将题目改成了多组数据,n在ll范围内,所以我就只讲提高版的做法. 链接:https://www.luogu.org/problem/show?pid=2233 ...
- HDU 4549 M斐波那契数列(矩阵快速幂)
题目链接:M斐波那契数列 题意:$F[0]=a,F[1]=b,F[n]=F[n-1]*F[n-2]$.给定$a,b,n$,求$F[n]$. 题解:暴力打表后发现$ F[n]=a^{fib(n-1)} ...
随机推荐
- 20135220谈愈敏Blog8_进程的切换和系统的一般执行过程
进程的切换和系统的一般执行过程 谈愈敏 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-100002 ...
- Opencv step by step - 加载视频
刚买了本 "学习Opencv" 这本书,慢慢看起来. 一开始就是加载视频了.当然了,首先你要有个视频 从这里下载了一个: tan@ubuntu:~$ wget http://www ...
- JavaScript实现MVVM之我就是想监测一个普通对象的变化
http://hcysun.me/2016/04/28/JavaScript%E5%AE%9E%E7%8E%B0MVVM%E4%B9%8B%E6%88%91%E5%B0%B1%E6%98%AF%E6% ...
- java之运算符
package com.simope.myTest; import java.util.HashMap; import java.util.Iterator; import java.util.Map ...
- 【niubi-job——一个分布式的任务调度框架】----niubi-job这下更牛逼了!
niubi-job迎来第一次重大优化 niubi-job是一款专门针对定时任务所设计的分布式任务调度框架,它可以进行动态发布任务,并且有超高的可用性保证. 有多少人半夜被叫起来查BUG,结果差到最后发 ...
- css圆角矩形及去掉空格属性
css圆角矩形 -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; 去掉空格 white-space:nowra ...
- [USACO2003][poj2185]Milking Grid(kmp的next的应用)
题目:http://poj.org/problem?id=2185 题意:就是要求一个字符矩阵的最小覆盖矩阵,可以在末尾不完全重合(即在末尾只要求最小覆盖矩阵的前缀覆盖剩余的尾部就行了) 分析: 先看 ...
- [c#基础]堆和栈
前言 堆与栈对于理解.NET中的内存管理.垃圾回收.错误和异常.调试与日志有很大的帮助.垃圾回收的机制使程序员从复杂的内存管理中解脱出来,虽然绝大多数的C#程序并不需要程序员手动管理内存,但这并不代表 ...
- 1、面向对象以及winform的简单运用(开篇)
面向对象概述: 要学习好面向对象,我们应该从三个问题入手: 1.什么是面向对象? 2.为什么要面向对象? 3.该怎么面向对象? 面向对象,首先要有一个对象,那么对象是什么呢? 对象的定义是人们要进行研 ...
- LINQ构建交叉表
最近碰到客户的一个需求.使用交叉表来显示客户数据.也就是以同时以行头和列头交叉形式显示数据内容.同时要求即使有些列没有数据,也需要显示该列内容,并设置默认值. 说明: “交叉表”对象是一个网格,用来根 ...