noip前冲刺阶段的机房模拟......随便搞搞
T1(签到题)
就随便看着1e9的数据..........什么O(n)、O(nlog(n)) 之类的数据就别想了吧.........
我们一看到xor,就应该可以马上反应过来其实可以拆位来做,因为一个数二进制下每一位对于答案的贡献是完全独立的,可以直接相加。
我们对于一位来说,肯定是只有0和1这两种位数,那么我们考虑何种情况下对答案是有贡献的。
首先,一对1和一对0是肯定没有贡献的,那么我们考虑一个1和一个0;
于是我们可以得到:假设这个数的这一位是1,那么肯定需要一个0才能使得这一个1对答案有贡献。
那么贡献是多少呢?
我们可以轻松得到0的个数*1的个数*(1<<i)*2
为什么要乘以2呢?
因为如果说1和0有贡献的话,0对1同样是有贡献的,所以我们计算两次就可以防止遗漏
接着我们考虑该如何统计每一位上[L,R]之间的1的个数
我们发现如果要从0开始数数,0、1、2、3、4、5……会出现以下情形
0000
0001
0010
0011
0100
0101
0110
0111
……
我们发现从低到高的话(从右向左),第一位的循环节长度是2(01 01 01)第二位是4(0011 0011 0011),第三位是8(00001111 00001111 00001111,而其中1、0个掺半。
如果我们直接根据L、R来考虑0、1的个数的话会非常的复杂,因为你不知道对于L来说到底处于当前循环节的位置。,R也同理
但是如果说我们使用1~R间的个数减去1~L-1的个数的话,由于0肯定是一个任意一位的循环节的开始位置,那么我们只需要处理R就好了
R就随便取下模就OK了
代码
#include
#define OP "xor"
#define LL long long
const int MOD=1e9+7;
int main()
{
std::freopen(OP".in","r",stdin);
std::freopen(OP".out","w",stdout);
int T;
std::scanf("%d",&T);
while(T--)
{
int l,r;
std::scanf("%d%d",&l,&r);
LL ans=0;
l--;
for(int i=0;(1<(1<(1<
T2(又一次超纲考博弈论........)
首先要搞清楚,这一道题虽然看上去和NIM游戏是如此的相似
但是并不一样.............
我们首先考虑简单的情况 (也就是部分分)
第一,当x、y、z很小的时候,我们可以考虑使用非常简单的博弈论基础内容,开一个三维数组来记录当前的x、y、z是必胜态或者是必败态,然后用必胜必败态的基础性质来转移(一个状态为必胜态当且仅当当前状态可以转移到一个必败态,一个状态为必败态当且仅当它能够转移到的所有状态均为必胜态)
这样的话时间复杂度为n^4
我们再来考虑只有两堆的情况(著名的威佐夫博弈)。
根据之前的做法打表,我们可以发现只有两堆的情况有一些特殊的性质,打个比方,我们打出只有两堆的情况时侯的前五项必败态,他们分别是
1 2 0
3 5 0
4 7 0
6 10 0
8 13 0
……
我们可以发现它们拥有的两个性质:
1、对于任意一个自然数,存在且仅存在一个自然数使得当前情况为必败态
2、对于任意一个必败态,其两堆石头的差值一定与任意必败态不同。
这两个性质都非常好证明
1、若对于自然数X,存在Y1,Y2使得其为必败态,我们假设Y1 X、Y2可以通过先手的操作使它变为X、Y1。 X、Y1为必败态,则后手必败,先手必胜,与X、Y2必败矛盾。 故对于任意一个自然数,存在且仅存在一个自然数使得当前情况为必败态。 2、对于自然数对(X1、Y1);(X2、Y2),两者均为必败态 ,且X1 先手拿到X2、Y2状态 先手通过操作使其变为X1、Y1 X1、Y1必败,则后手必败,先手必胜,与X2、Y2必败矛盾 故对于任意一个必败态,其两堆石头的差值一定与任意必败态不同。 至此证毕 两者的证明其实真正依赖的定理都是博弈论的基础性质:一个必败态只能转移到必胜态,不可能转移到必败态,否则与它是必败态完全矛盾。 知道了这一个性质,当只有两堆棋子的时候我们就可以直接n^2for循环得到任意的值对应的必败态,如果另外的一个值是其对应的必败态的值则就输出No,否则输出Yes 至此,我们拥有了这道题目的70pts算法。 而实质意义上,两堆的情况稍作推理就可以转移至三堆的情况 对于已经确定的前两堆石子(a,b),存在且仅存在一个c使得这个三元组为必败态,其余均为必胜态 然后我们可以发现,对于同一个c,a、b之间的差值仍然不变。 于是我们定于f[a][b],其含义为当前两堆石头为a,b时所对应的唯一的使得当前状态成为必败态的第三堆石头 那么我们考虑从小到大枚举C 我们可以发现,对于C来说,由于从小到大枚举,那么f[a][b]=k且k 根据以上性质,我们可以得到:当存在f[a][b]=k且k 所以我们记录一下这些特殊的必定不等的值,再判断一下a、b出现次数是否大于1以及他们的差值是否只出现一次,就可以得到a、b了 然后输入x、y、z,直接判断f[x][y]是否等于z,如果等于输出No(必败),否则输出Yes; 如果你完美地看出了性质,这本来是不是很难的题目..... 但是性质贼TM难想,属于不知道就寸步难行(出题人原话)的那种 区间贡献的系数只有2、0、-2三种,根本不用考虑到底放在具体哪个区间,只需要考虑放在哪种区间即可......... 知道这个性质之后真的随随便便都能过............ #include
#include