[vijos1554&bzoj1411]硬币游戏<快速幂>
题目链接:https://vijos.org/p/1554
http://www.lydsy.com/JudgeOnline/problem.php?id=1411
这题真的淫*QAQ。。。
一看题还以为是啥水题,结果啊,是个规律题
我们先来解释一下样例
20202010101010101020 0
01010201010101010201 1
10102020101010102020 2
01020102010101020102 3
20202020201010202020 4
01010101020102010101 5
10101010202020201010 6
01010102010101020101 7
10101020201010202010 8
01010201020102010201 9
10102020202020202020 10
01020101010101010102 11
这后面的数字表示的是第几次操作
然后可以开始找规律了。。。。。。。。。
盯-----------------------------------------------------------------------------------------------------
这个看起来头有点痛,我们优化一波来看
20202010101010101020 0
10102020101010102020 2
20202020201010202020 4
10101010202020201010 6
10101020201010202010 8
10102020202020202020 10
其实我们就可以发现,这个每两次操作,硬币的位置是不会变的,变的只是正反面
然后我们在把这个图继续变换
20202010101010101020 0
10102020101010102020 2
20202020201010202020 4
10101020201010202010 8
我们只留下了2^k次方这些操作
就可以发现,第2^k次方次操作中,第i个数是由最开始的i-2^k和i+2^k这两个数来决定的
所以对于操作次数T
要把T分解成2^k+2^k-1+···+2^1+1这种形式的
其实吧,这就是快速幂
然后快乐的写一个快速幂模板就过了
只是注意一下T是2^60,要用long long存
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<iostream>
5 #include<cstdlib>
6 #include<queue>
7 #include<cmath>
8 #define maxn 200005
9 using namespace std;
10
11 int n;
12 long long x,d=1;
13 int a[maxn*2],b[maxn*2];
14
15 int did(int pos,long long dis){
16 int l=((pos-dis)%n+n)%n,r=(pos+dis)%n;
17 //pos-dis有可能<-n;
18 if(l==0)l=n;if(r==0)r=n;
19 if(a[l]==0)return 0;
20 if(!(a[l]^a[r]))return 1;
21 return 2;
22 }
23
24 void work(){
25 while(x){
26 if(x&1){
27 for(int i=1;i<=n;i++)
28 b[i]=did(i,d);
29 for(int i=1;i<=n;i++)
30 a[i]=b[i];
31 }
32 x>>=1;d<<=1;
33 }
34 }
35
36 int main(){
37 scanf("%d%lld",&n,&x);n<<=1;
38 for(int i=1;i<=n;i+=2){
39 scanf("%d",&a[i]);
40 }
41 work();
42 for(int i=1;i<n;i++){
43 printf("%d ",a[i]);
44 }printf("%d",a[n]);
45 }
【总结】
然后看见我的注释没,我就在那里卡了很久,因为我最开始的L是(pos-dis+n)%n;
然后光荣爆炸,毕竟,我没算到pos-dis的绝对值可能是小于n的啊
所以那个位置的正确写法((pos-dis)%n+n)%n;