51nod 1661 黑板上的游戏(yjq魔改ver【x【博弈,稍微数学推一下
2016-09-10 23:57
197 查看
题意差不多就是那样……但是输出的方案(题面原话)是→“我们需要使得擦去的数字下标尽量大,在此前提下,
我们希望写上的数字尽量大”
总之我胡搞乱搞只有52分,嗨呀好气啊,std是yjq的代码……yjq说自己看不懂当时写的啥了……于是…………唉说多了都是泪【x
嗯……我手推SG值玩了一张纸,写完代码发现……woc看错题了,有理数除法看成了下取整,GG
又玩了一张纸的SG值【我是智障吗】然后和电脑对拍【我果然是智障】
……其实手推比较容易找规律,讲真
总之就看出了这个鬼畜的规律
1.当x%k==1时,他的SG值是从前面递归搞过来的,并没有更新【反正手跑一下就显然了
2.其他时候,SG值是x-x/k,除法上取整
于是开始考虑如何得到那个【最大的下标】
1.SG值不是单调的,所以并不能单纯地用sg(a[i])>sum_xor,显然sg[a[i]]==sum_xor也是可以卡的【虽然yjq表示自己就是这么写的 …………
2.只有x%k==1的时候才会出现一个不单调的点(下陷),其他时候SG值都是x-x/k,而且会发现,当x%k==1时,用通式算得的值和SG(x-1)应该是一样的【证明什么的……应该是显然吧,x'比x大1,但上取整的除法结果也大了1】,所以我们可以把SG值序列当成单调不降的,并且直接用通式算出可以转移到的最大sg值(max_sg)
3.只要max_sg(a[i])>=sum_xor^a[i],就可以通过修改当前位置的值来得到最优答案,总之从右往左for一遍,判一下就好
然后是那个最大的解
1.可以直接for,T不T看脸
2.可以二分,然而基本写挂了,有个大爷写的l到r的区间小于等于1e5直接暴力for,看起来挺靠谱但是复杂度有毒
3.yjq表示你们啊naive,作为一个长者我写的是O(1)的【x
4.对于一个式子g=x-ceil(x/k),我们设x=ak+b+1 (b∈[0,k-1]),那么,ceil(x)=a+1,于是g=ak+b+1-a-1=a(k-1)+b
g=a(k-1)+b;
1) 如果g%(k-1)==0 那么b也等于0,说明x=ak+1=g/(k-1)*k+1,但是这样得到的解显然不是合法的(因为在x%k==1时,这是一个凹下去的点),但之前我们证明了在此时 SG(x-1)==SG(x),所以可以得到一个解(x-1)
2) 在其他情况下,可以求得b=g%(k-1),所以x=ak+1+b=g/(k-1)*k + 1 + g%(k-1)
5.当前我们得到了一个解,但不一定是最优的,于是根据当时手跑SG值得到的结论,对于一个数a,SG(a)==SG(ak+1),于是在小于当前修改位置上的值的情况下,稍微递推一下就好,因为一直在*k,所以最坏复杂度也是O(log值域)的
我觉得我一个下午就推了这一道题真是太菜了,但是总觉得可以hack一下std了迷之开心【有毒吧你】
最后感谢出题人yjq考试T1暴力分竟然可以用轻度优化水80,重度优化直接A
我们希望写上的数字尽量大”
总之我胡搞乱搞只有52分,嗨呀好气啊,std是yjq的代码……yjq说自己看不懂当时写的啥了……于是…………唉说多了都是泪【x
嗯……我手推SG值玩了一张纸,写完代码发现……woc看错题了,有理数除法看成了下取整,GG
又玩了一张纸的SG值【我是智障吗】然后和电脑对拍【我果然是智障】
……其实手推比较容易找规律,讲真
总之就看出了这个鬼畜的规律
1.当x%k==1时,他的SG值是从前面递归搞过来的,并没有更新【反正手跑一下就显然了
2.其他时候,SG值是x-x/k,除法上取整
于是开始考虑如何得到那个【最大的下标】
1.SG值不是单调的,所以并不能单纯地用sg(a[i])>sum_xor,显然sg[a[i]]==sum_xor也是可以卡的【虽然yjq表示自己就是这么写的 …………
2.只有x%k==1的时候才会出现一个不单调的点(下陷),其他时候SG值都是x-x/k,而且会发现,当x%k==1时,用通式算得的值和SG(x-1)应该是一样的【证明什么的……应该是显然吧,x'比x大1,但上取整的除法结果也大了1】,所以我们可以把SG值序列当成单调不降的,并且直接用通式算出可以转移到的最大sg值(max_sg)
3.只要max_sg(a[i])>=sum_xor^a[i],就可以通过修改当前位置的值来得到最优答案,总之从右往左for一遍,判一下就好
然后是那个最大的解
1.可以直接for,T不T看脸
2.可以二分,然而基本写挂了,有个大爷写的l到r的区间小于等于1e5直接暴力for,看起来挺靠谱但是复杂度有毒
3.yjq表示你们啊naive,作为一个长者我写的是O(1)的【x
4.对于一个式子g=x-ceil(x/k),我们设x=ak+b+1 (b∈[0,k-1]),那么,ceil(x)=a+1,于是g=ak+b+1-a-1=a(k-1)+b
g=a(k-1)+b;
1) 如果g%(k-1)==0 那么b也等于0,说明x=ak+1=g/(k-1)*k+1,但是这样得到的解显然不是合法的(因为在x%k==1时,这是一个凹下去的点),但之前我们证明了在此时 SG(x-1)==SG(x),所以可以得到一个解(x-1)
2) 在其他情况下,可以求得b=g%(k-1),所以x=ak+1+b=g/(k-1)*k + 1 + g%(k-1)
5.当前我们得到了一个解,但不一定是最优的,于是根据当时手跑SG值得到的结论,对于一个数a,SG(a)==SG(ak+1),于是在小于当前修改位置上的值的情况下,稍微递推一下就好,因为一直在*k,所以最坏复杂度也是O(log值域)的
我觉得我一个下午就推了这一道题真是太菜了,但是总觉得可以hack一下std了迷之开心【有毒吧你】
最后感谢出题人yjq考试T1暴力分竟然可以用轻度优化水80,重度优化直接A
#include<bits/stdc++.h> #define MAXN 100005 using namespace std; int n;long long k; long long a[MAXN],sg[MAXN]; long long SG(long long x){ while(x>k&&!((x-1)%k)) x=(x-1)/k; return x-1-(x-1)/k; } long long max_SG(long long x){ return x-1-(x-1)/k; } long long now_xor=0; long long find_x(long long sgg,long long lmt){ long long tmp=sgg/(k-1)*k+1; if(sgg==0) tmp=1; else if(sgg%(k-1)) tmp+=sgg%(k-1); else --tmp; while((lmt-1)/tmp>k) tmp=tmp*k+1; return tmp; } int main(){ scanf("%d%lld",&n,&k); for(int i=1;i<=n;++i) scanf("%lld",a+i),sg[i]=SG(a[i]),now_xor^=sg[i]; if(!now_xor) return puts("Bob"),0; else printf("Alice "); for(int i=n;i;--i){ if(max_SG(a[i])>=(now_xor^sg[i])){ long long tmp=now_xor^sg[i]; tmp=find_x(tmp,a[i]); printf("%d %lld",i,tmp); break; } } return 0; }
相关文章推荐
- 51nod 1661 黑板上的游戏(博弈sg函数找规律)
- 51NOD 1661 黑板上的游戏(博弈 找规律)——算法马拉松17(告别奥运)
- 51nod-1661 1661 黑板上的游戏(组合游戏)
- Nim游戏的一个扩展——51nod 1661 黑板上的游戏+LA 5059 Playing With Stones
- 51Nod-1661-黑板上的游戏
- 51NOD 1417 天堂里的游戏 博弈 (数学题)
- 51nod - 1661 黑板上的游戏 - 博弈论
- 51nod 1661: 黑板上的游戏(sg函数 找规律)
- 51nod 1185 威佐夫游戏 V2(威佐夫博弈)
- 51nod 1070 Bash游戏 V4(博弈——找规律)
- 51Nod-1066 Bash游戏(博弈问题)
- 51nod 1490 多重游戏 (博弈)
- 如何赢得数学游戏(博弈问题)
- 51nod 1072 博弈 威佐夫游戏
- 自己做的几个小软件(数学工具和游戏),用C/C#制作,用到许多相关的C#技术细节,可以免费提供下载,感兴趣的,来看一下
- 51nod 1185 威佐夫游戏 V2 (博弈+大数乘法模拟)
- 51nod 40 Bash游戏 博弈,打表
- 两人取石子游戏 组合数学-博弈问题
- 51nod 1070 Bash游戏 V4(博弈——找规律)
- 51Nod-棋子游戏(博弈问题)