用户工具

站点工具


2020-2021:teams:legal_string:组队训练比赛记录:contest12

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:组队训练比赛记录:contest12 [2021/08/10 16:54]
jxm2001
2020-2021:teams:legal_string:组队训练比赛记录:contest12 [2021/08/14 10:56] (当前版本)
lgwza [补题情况]
行 5: 行 5:
 ^  题目 ​ ^  蒋贤蒙 ​ ^  王赵安 ​ ^  王智彪 ​ ^ ^  题目 ​ ^  蒋贤蒙 ​ ^  王赵安 ​ ^  王智彪 ​ ^
 |  A  |  0  |  0  |  0  |  |  A  |  0  |  0  |  0  | 
-|  B  |  2  |  ​ ​| ​ 0  | +|  B  |  2  |  ​ ​| ​ 0  | 
 |  C  |  0  |  0  |  0  |  |  C  |  0  |  0  |  0  | 
 |  D  |  0  |  0  |  0  |  ​ |  D  |  0  |  0  |  0  |  ​
-|  E  |  ​ ​| ​ 0  |  ​ ​|  ​+|  E  |  ​ ​| ​ 0  |  ​ ​|  ​
 |  G  |  0  |  0  |  0  |  ​ |  G  |  0  |  0  |  0  |  ​
-|  J  |  2  |  ​ ​| ​ 0  |   +|  J  |  2  |  ​ ​| ​ 0  |   
-|  K  |  2  |  ​ ​| ​ 0  | +|  K  |  2  |  ​ ​| ​ 0  | 
  
 ====== 题解 ====== ====== 题解 ======
行 177: 行 177:
 } }
 </​code>​ </​code>​
 +</​hidden>​
 +
 +===== E. xay loves nim  =====
 +
 +==== 题意 ====
 +
 +给了 $n$ 堆石子和 $m$ 个可以取走的石子的数量,记为 $x_{i}$ ,除了这 $m$ 种石子,还可以取莫比乌斯函数值为 $1$ 的数量石子。同时给出这 $n$ 堆石子的数量范围 $[l_{i},​r_{i}]$ ​ ,求所有的情况中,先手必胜的局数,局面不同当且仅当存在一堆石子在两个局面中数量不同。
 +
 +$1≤n≤10^{6},​1≤l_{i},​r_{i}≤10^{5},​1≤m≤5,​1≤x_{i}≤10^{5}$
 +
 +==== 题解 ====
 +
 +大综合题,显然需要会莫比乌斯反演(废话),还需要会博弈论的 $sg$ 那套理论,先手必胜当且仅当所有的 $sg$ 值异或起来不为 $0$ 。听出题人说 $sg$ 值最高不会超过 $230$ ,但是现场的时候怎么知道嘛...
 +
 +显然需要先筛出来 $1$ 到 $100000$ 的莫比乌斯函数值,才能知道哪些能加进去,然后再把 $m$ 种数字也放进去,然后就是看每个状态的后继状态,这里也是学到了可以暴力搞。
 +
 +对于每一个新的值 $i$ ,搞一个数组,看这个值的后继状态有没有 $sg$ 为这个值的,如果有需要继续找,直到找不到,根据 $mex$ 那套理论,就是此时的 $sg$ 了。然后 $i$ 加上刚才放进去的那些数的后继状态可以到达 $i$ ,于是这些状态的后继 $sg$ 值可以有现在这个值,这里我们只关心能不能有,所以可以用 $bitset$ 优化一下,这部分的复杂度是 $O({\frac {100000^{2}} w}+256×100000)$ ,这里本来要写 $230$ 的,但是后面需要变成 $256$ 。
 +
 +于是我们处理出了所有石子数的 $sg$ 值,接下来对于每一堆石子,我们可以求出来,他们这个范围内,分别有多少个 $sg$ 值为 $0$ 的,有多少个 $sg$ 值为 $1$ 的,依次类推。
 +
 +然后我们需要关心有多少个 $a[1]$ ^ $a[2]$ ^ $…$ ^ $a[n]≠0$ ,这玩意显然可以看成 $FWT$ 。我们先统计出每个区间内有多少个 $sg$ 值为 $i$ 的,这显然前缀和就可以。然后我们相当于看 $n$ 个多项式相乘,每个多项式的幂次是各个 $sg$ 值,系数是有多少个状态的 $sg$ 值是这个值。如果对于每个求 $FWT$ 再乘起来,最后再 $IFWT$ 。我们需要开到 $256$ ,这就照应了前面。算了一下,单个复杂度是 $O(256×log_{2}(256))=O(2048)$ ,然后 $n$ 个就是 $2×10^{9}$ 的,这显然是自杀行为。
 +
 +然后 $oi-wiki$ 上一段话刷新了我对 $FWT$ 的认知:若我们令 $i\&j$ 中 $1$ 的奇偶性为 $i$ 与 $j$ 的奇偶性,于是 $i$ 与 $k$ 的奇偶性异或 $j$ 与 $k$ 的奇偶性等于 $i$ ^ $j$ 与 $k$ 的奇偶性。然后可以得到异或的 $FWT$ : $A_{i}=\sum_{C_{1}}A_{j}-\sum_{C_{2}}A_{j}$ , $C_{1}$ 表示 $i\&j$ 的奇偶性为偶, $C_{2}$ 表示 $i\&j$ 的奇偶性为奇。(其实记住就行...)
 +
 +又因为 $sg$ 的范围有限,所以我们可以先预处理出每个数的二进制有多少位为 $1$ (或者直接 $\_\_builtin\_popcount$ 也可以)。
 +
 +然后对于前缀和数组,就不能直接暴力加一了,判断两者与的奇偶性,如果为偶,则加一,不然减一。然后这样就直接把每一堆的 $FWT$ 数组给求完了,复杂度变成 $O(256n)$ ,而不是原来的 $O(2048n)$ ,再全乘起来求一个 $IFWT$ 就可以了,整个这部分的复杂度都是 $O(256n)$ 的,最后对于所有 $sg$ 值不为 $0$ 的结果都加起来就是答案了。
 +
 +另外这题卡常!前缀和数组必须大的做第一维,我不倒过来会 $t$ 掉绝大多数数据,倒过来效率就第一了...
 +
 +<hidden 代码>
 +
 +<code cpp>
 +
 +const int maxn=100000,​N=1e6+10,​maxm=256,​MOD=1e9+7,​inv2=500000004;​
 +bool check[maxn+1];​
 +int prime[maxn+1],​mu[maxn+1];​
 +int tot,​n,​m,​ls[N],​rs[N],​sg[maxn+1],​sum[maxn+1][maxm+1],​ans[maxm+1],​o[maxm+1];​
 +bitset<​maxn+1>​ t,b[maxm];
 +
 +
 +void Moblus() {
 + mu[1]=1;
 + for(int i=2; i<=maxn; i++) {
 + if(!check[i]) {
 + mu[i]=-1;​
 + prime[tot++]=i;​
 + }
 + for(int j=0; j<tot; j++) {
 + if(i*prime[j]>​maxn) break;
 + check[i*prime[j]]=true;​
 + if(i%prime[j]==0) {
 + mu[i*prime[j]]=0;​
 + break;
 + } else {
 + mu[i*prime[j]]=-mu[i];​
 + }
 + }
 + }
 +}
 +
 +void xor_FWT(int *P,int opt,int N) {
 + for(int i=2; i<=N; i<<​=1)
 + for(int p=i>>​1,​j=0;​ j<N; j+=i)
 + for(int k=j; k<j+p; ++k) {
 + int x=P[k],​y=P[k+p];​
 + P[k]=((ll)x+y)%MOD;​
 + P[k+p]=((ll)x-y+MOD)%MOD;​
 + if(opt==-1)P[k]=(ll)P[k]*inv2%MOD,​P[k+p]=(ll)P[k+p]*inv2%MOD;​
 + }
 +}
 +
 +void init() {
 + o[0]=0;
 + for(int i=1;​i<​maxm;​i++)o[i]=o[i>>​1]+(i&​1);​
 + for(int i=1; i<=maxn; i++) {
 + if(mu[i]==1)t.set(i);​
 + }
 + for(int i=0; i<=maxn; i++) {
 + sg[i]=0;
 + while(b[sg[i]][i]) sg[i]++;
 + b[sg[i]]|=(t<<​i);​
 + }
 +}
 +
 +int main() {
 + Moblus();
 + read(n);​read(m);​
 + for(int i=1; i<=n; i++) read(ls[i]),​read(rs[i]);​
 + for(int i=1,tmp; i<=m; i++) read(tmp),​t.set(tmp);​
 + init();
 + for(int i=0; i<=maxn; i++)
 + for(int j=0; j<maxm; j++)
 + if(!(o[sg[i]&​j]&​1))sum[i][j]=1;​
 + else sum[i][j]=MOD-1;​
 + for(int i=1; i<=maxn; i++) {
 + for(int j=0; j<maxm; j++) {
 + sum[i][j]=sum[i][j]+sum[i-1][j];​
 + if(sum[i][j]>​=MOD) sum[i][j]-=MOD;​
 + }
 + }
 + for(int i=0; i<maxm; i++)ans[i]=1;​
 + for(int i=1; i<=n; i++)
 + for(int j=0; j<maxm; j++)
 + ans[j]=(ll)ans[j]*(sum[rs[i]][j]-sum[ls[i]-1][j])%MOD;​
 + xor_FWT(ans,​-1,​maxm);​
 + ll sum=0;
 + for(int i=1; i<maxm; i++) {
 + sum=sum+ans[i];​
 + if(sum>​=MOD) sum-=MOD;
 + }
 + printf("​%lld\n",​(sum+MOD)%MOD);​
 + return 0;
 +}
 +
 +</​code>​
 +
 </​hidden>​ </​hidden>​
  
行 319: 行 436:
 对每次询问的 $a[l\sim r]$,令 $a_{l-1}=0,​a_{r+1}=0$,设 $b_i=a_i-a_{i-1}(l\le i\le r+1)$。 对每次询问的 $a[l\sim r]$,令 $a_{l-1}=0,​a_{r+1}=0$,设 $b_i=a_i-a_{i-1}(l\le i\le r+1)$。
  
-于是每次操作等价于选取一对 $l\le i,j\le r+1$,$b_i\equiv b_i+1\bmod k,b_j\equiv b_j+1\bmod k$。+于是每次操作等价于选取一对 $l\le i,j\le r+1$,$b_i\equiv b_i+1\bmod k,b_j\equiv b_j-1\bmod k$。
  
 同时,$\sum_{i=l}^{r+1} b_i=a_{r+1}-a_{l-1}=0$,最终目标是将 $b_i$ 全部变为 $0$。在不考虑取模的情况下,最小费用显然为 $\cfrac {\sum_{i=l}^{r+1}|b_i|}2$。 同时,$\sum_{i=l}^{r+1} b_i=a_{r+1}-a_{l-1}=0$,最终目标是将 $b_i$ 全部变为 $0$。在不考虑取模的情况下,最小费用显然为 $\cfrac {\sum_{i=l}^{r+1}|b_i|}2$。
2020-2021/teams/legal_string/组队训练比赛记录/contest12.1628585697.txt.gz · 最后更改: 2021/08/10 16:54 由 jxm2001