[考试反思]0506省选模拟89:无事

难得没挂分。。。通过卡常水了个$rk1$

$T1$是博弈论,打个$SG$表然后倒没啥扩展就是要写个高精。

$T2$啥都不会暴拆式子交暴力。最开始$OJ$又波动了干掉我$5$分重测就回来了。

$T3$打的$35$暴力然后看着只有$5 \times 10^4$的数据范围蠢蠢欲动于是大力卡常$n^2$多拿了$10$分。

倒也没啥水平就是纯粹想不想写的问题吧。。。谁还不会卡常啊。。。

 

T1:石子

大意:$m$堆石子,每次可以选一堆,假如剩下$x$个那么可以拿走$d$个要求$d \neq x,d|x$。不能拿的人输。问每堆石子最多$n$个则有多少种先手必胜局面。$n\le 10^{10000},m \le 10^{18}$

博弈论。每堆互不影响。所以考虑每一堆的$SG$异或起来就行。

考虑一堆,打表发现对于一个数$x=a \times 2^b$($a$是奇数)。则$SG(x)=b$

对于$x=1$显然。

对于一个奇数,它的所有决策都是拿走奇数个,剩余状态是偶数,$SG>0$。$mex$之后可知$SG(x)$当$x$为奇数时为零。

对于一个偶数,它可能的决策是拿走$2^0,2^1,2^2,...,2^b$。(可能最后一项是非法的,当$a=1$的时候)

前面乘上一个奇系数没影响。这样所到达的状态都恰好是$2^0,2^1,2^2...2^b$的倍数。

所对应的$SG$分别是$0,1,2,...,b-1,?$。其中$?$是一个$>b$的数。

所以$SG=b$。归纳得证。

所以同时也就知道了$SG$是$log_2n$级别的。大约是$30000$

然后我们需要知道每种$SG$有多少个数。也就是:有多少奇数,有多少$2$的倍数而不是$4$的倍数。。。说白了就是$lowbit$

只需要每次$a=\lceil \frac{n}{2} \rceil$。然后$n \leftarrow \frac{n}{2}$

这里需要高精除低精是$log_2^2n$的有点大。但是只要顺手写个十亿进制压位常数就除$9$了就没问题了。

然后剩下的就是$30000$个$SG$。讲$m$个这玩意异或起来结果不是$0$的方案数。$FWT$板子。

叠个快速幂。总复杂度$O(\frac{log^2_2n}{9} + log_2nlog(log_2n) + log_2nlog\ m)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 998244353
 4 int mo(int x){return x>=mod?x-mod:x;}
 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 6 #define S 1<<20
 7 int lg,SG[S],ans[S],Ans,n[S],bn,rev[S],len; long long m; char N[S];
 8 void FWT(int*a,int op=1){
 9     for(int i=0;i<len;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
10     for(int i=1;i<len;i<<=1)for(int j=0;j<len;j+=i<<1)
11         for(int k=j,x,y;k<j+i;++k)
12             x=a[k],y=a[k+i],a[k]=mo(x+y),a[k+i]=mo(x+mod-y);
13     if(op==-1)for(int iv=qp(len,mod-2),i=0;i<len;++i)a[i]=1ll*a[i]*iv%mod;
14 }
15 int main(){
16     scanf("%s%lld",N,&m); len=strlen(N); reverse(N,N+len);
17     for(int j=len-1;~j;--j)n[j/9+1]=n[j/9+1]*10+N[j]-48;
18     len=(len-1)/9+1;
19     for(lg=0;len;++lg){
20         SG[lg]=n[1]&1; int x=0;
21         for(int j=len;j;--j)n[j-1]+=(n[j]&1)*1000000000,n[j]>>=1,x=(x*1000000000ll+n[j])%mod;
22         SG[lg]+=x; while(len&&!n[len])len--;
23     }
24     ans[0]=len=1;
25     while(len<=lg)len<<=1;
26     for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0);
27     FWT(ans);FWT(SG);
28     for(;m;m>>=1){
29         if(m&1)for(int i=0;i<len;++i)ans[i]=1ll*ans[i]*SG[i]%mod;
30         for(int i=0;i<len;++i)SG[i]=1ll*SG[i]*SG[i]%mod;
31     }FWT(ans,-1);
32     for(int i=1;i<len;++i)Ans=mo(Ans+ans[i]);
33     printf("%d\n",Ans);
34 }
View Code

 

T2:奥术

大意:数串。支持复制一段区间到另一段,询问一个子串,它的所有子串的值的和。$n,Q \le 10^5$

发现答案是关于$1,l,10^r,l\times 10^r$的一次项式的和。线段树维护暴力修改。

然后赋值操作可以可持久化平衡树。需要定期重构。写个毛线。

然而貌似不是完全不能理解。贴个$std$方便以后回来看。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cctype>
  4 #include<algorithm>
  5 #define rep(i,s,t) for(int i=s;i<=t;i++)
  6 #define dwn(i,s,t) for(int i=s;i>=t;i--)
  7 using namespace std;
  8 inline int read(){
  9     int x=0,f=1;char c=getchar();
 10     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
 11     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
 12     return x*f;
 13 }
 14 typedef long long ll;
 15 const int maxn=160010,mod=998244353,maxnode=1500010;
 16 int ToT,ls[maxnode],siz[maxnode],rs[maxnode];
 17 int qpow(int n,int m){
 18     int ans=1;
 19     for(;m;m>>=1,n=(ll)n*n%mod) if(m&1) ans=(ll)ans*n%mod;
 20     return ans;
 21 }
 22 int n,m,b,f[maxn],pw[maxn];
 23 char s[maxn];
 24 struct Node {
 25     int axb,ax,xb,x,l;
 26     Node(int v=0){l=1;x=ax=v;axb=xb=(ll)b*v%mod;}
 27     Node operator+(Node b){
 28         if(!b.l) return *this;
 29         if(!l) return b;
 30         Node c(0);
 31         c.l=l+b.l;
 32         c.x=(x+b.x)%mod;
 33         c.ax=((ax+b.ax)%mod+(ll)l*b.x%mod)%mod;
 34         c.xb=(b.xb+(ll)xb*pw[b.l]%mod)%mod;
 35         c.axb=(ll)axb*pw[b.l]%mod;
 36         (c.axb+=((ll)l*b.xb%mod+b.axb)%mod)%=mod;
 37         return c;
 38     }
 39     int ans(){
 40         int res=(axb-ax+mod)%mod;
 41         res=(ll)res*qpow(((ll)l*(l+1)/2)%mod*(b-1)%mod,mod-2)%mod;
 42         return res;
 43     }
 44 }sumv[maxnode];
 45 int val[maxnode];
 46 void copy(int&y,int x){
 47     ls[y]=ls[x];rs[y]=rs[x];siz[y]=siz[x];
 48     sumv[y]=sumv[x];val[y]=val[x];
 49 }
 50 void maintain(int x){
 51     siz[x]=siz[ls[x]]+siz[rs[x]]+1;
 52     sumv[x]=sumv[ls[x]]+(Node(val[x]));
 53     sumv[x]=sumv[x]+sumv[rs[x]];
 54 }
 55 void split(int o,int k,int&left,int&right){
 56     if(!k) {left=0,right=o;return;}
 57     if(k==siz[o]) {left=o,right=0;return;}
 58     int z=++ToT;copy(z,o);
 59     if(siz[ls[z]]>=k) {
 60         right=z;split(ls[z],k,left,ls[right]);
 61         maintain(right);
 62     }else{
 63         left=z;split(rs[z],k-siz[ls[z]]-1,rs[left],right);
 64         maintain(left);
 65     }
 66 }
 67 int Rand(){return (rand()<<15)|rand();}
 68 int merge(int x,int y){
 69     if(!x) return y;
 70     if(!y) return x;
 71     int z=++ToT;
 72     if(Rand()%(siz[x]+siz[y])<=siz[x]){
 73         copy(z,x);rs[z]=merge(rs[z],y);
 74         maintain(z);
 75         return z;
 76     }else{
 77         copy(z,y);ls[z]=merge(x,ls[z]);
 78         maintain(z);
 79         return z;
 80     }
 81 }
 82 void build(int&o,int l,int r){
 83     o=0;if(l>r) return;
 84     int mid=l+r>>1;o=++ToT;val[o]=s[mid]-'0';
 85     build(ls[o],l,mid-1);build(rs[o],mid+1,r);
 86     maintain(o);
 87 }
 88 int cnt;
 89 void print(int o){
 90     if(!o) return;
 91     print(ls[o]);
 92     s[++cnt]=val[o]+'0';
 93     print(rs[o]);
 94 }
 95 int main() {
 96     n=read();m=read();b=10;sumv[0].l=0;
 97     f[1]=1;pw[1]=b;pw[0]=1;
 98     rep(i,1,n+1) f[i+1]=((ll)f[i]*b%mod+1)%mod,pw[i+1]=(ll)pw[i]*b%mod;
 99     scanf("%s",s+1);
100     int root,o,left,mid,right,tmp;
101     build(root,1,n);
102     while(m--) {
103         int t=read(),l=read(),r=read();
104         if(t==1) {
105             split(root,l-1,left,o);
106             split(o,r-l+1,mid,right);
107             printf("%d\n",sumv[mid].ans());
108         }else{
109             int x=read()+1;swap(l,r);
110             split(root,l-1,left,o);
111             split(o,x,mid,right);
112             split(root,r-1,left,o);
113             split(o,x,tmp,right);
114             root=merge(left,mid);
115             root=merge(root,right);
116         }
117         if(m%10000==0) {
118             cnt=ToT=0;
119             print(root);
120             build(root,1,n);
121         }
122     }
123 }
View Code

 

T3:排列

大意:求所有满足最长上升/下降子串长度$\le 2$的长度介于$[L,R]$之间的排列个数。$R \le 10^6$

首先这差不多是个原题。可以用同样的方法做。只不过最后统计答案的时候稍微改变一下。

当时计数的是对于某个特定长度。换成一个区间后,发现是卷积形式。。。$O(nlogn)$

题解做法是,首先设$f_n$表示长度为$n$的满足条件的排列个数。

发现$W,M$形排列是相对的只要计数其中一种最后再乘$2$即可。(特殊考虑$n=1$)

我们假如只计数$W$形。枚举数字$n$所在的位置,得到$f_n= \sum\limits_{i=1}^{\frac{n}{2}} \binom{n-1}{2i-2} f_{2i-2} f_{n-(2i-1)}$

同理枚举数字$1$的位置,得到$f_n=\sum\limits_{i=1}^{\frac{n}{2}} \binom{n-1}{2i-1} f_{2i-1} f_{n-2i}$

二式相加得到$f_n =\sum\limits_{i=1}^{n} \binom{n-1}{i-1} f_{i-1} f_{n-i}$

拆开组合数得到$\frac{2f_n}{(n-1)!} = \sum\limits_{i=0}^{n-1} \frac{f_i}{i!} \frac{f_{n-i-1}}{(n-i-1)!}$

很像指数型生成函数。但是左边错位了且还有系数。错位可以用导数处理,故得到$2F'=F^2+1$

$\frac{F'}{F^2+1}=\frac{1}{2}$

我们有$tan'(x)=(\frac{sin}{con})'(x) = \frac{sin^2(x)+cos^2(x)}{cos^2(x)}=1+tan^2(x)$

然后就有设$arctan'(y)=\frac{1}{1+y^2}$。考虑$y=tan(x)$,定义域仍然是$R$。

所以其实也就是$x$关于$tan(x)$的导数。

所以也就是$tan(x)$关于$x$的导数的倒数。

所以也就是$\frac{1}{1+tan^2(x)}$。代回得到$\frac{1}{1+y^2}$

所以发现原式就是$arctan'(F(x))$的形式。(复合函数求导)

所以我们得到$arctan'(F(x))=\frac{1}{2}$。

所以有$arctan(F(x))=\frac{1}{2}x+c$(根据导数还原原函数,然而还原时可能会多出来一个常数,是在求导时消失的常数项)

所以$F(x)=tan(\frac{1}{2}x+c)$

显然有$F(0)=1$。带入得知$c=\frac{\pi}{4}$

$tan(\frac{1}{2}x+\frac{\pi}{4})$

$ = \frac{sin(\frac{1}{2}x+\frac{\pi}{4})}{cos(\frac{1}{2}x+\frac{\pi}{4})}$

$ = \frac{sin(\frac{1}{2}x)+cos(\frac{1}{2}x)}{cos(\frac{1}{2}x)-sin(\frac{1}{2}x)}$

$ = \frac{sin^2(\frac{1}{2}x)+cos^2(\frac{1}{2}x)+2sin(\frac{1}{2}x)cos(\frac{1}{2}x)}{cos^2(\frac{1}{2}x)-sin^2(\frac{1}{2}x)}$

$=\frac{1+sin(x)}{cos(x)}$

然后只需要级数求和。。。

$sin(x)=\sum (-1)^{i-1} \frac{x^{2i-1}}{(2i-1)!}$

$cos(x)=\sum (-1)^i \frac{x^{2i}}{(2i)!}$

然后多项式求逆就没了。$O(nlogn)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 998244353
 4 #define S 1<<21
 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 6 int mo(int x){return x>=mod?x-mod:x;}
 7 int rev[S],a[S],r[S],L,R,len,X[S],fac[S],inv[S],ans;
 8 void NTT(int*a,int op=1){
 9     for(int i=0;i<len;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
10     for(int i=1;i<len;i<<=1)for(int j=0,w=qp(3,(mod-1)/i/2*op+mod-1);j<len;j+=i<<1)
11         for(int k=j,t=1,x,y;k<j+i;++k,t=1ll*t*w%mod)
12             x=a[k],y=1ll*a[k+i]*t%mod,a[k]=mo(x+y),a[k+i]=mo(mod+x-y);
13     if(op==-1)for(int i=0,iv=qp(len,mod-2);i<len;++i)a[i]=1ll*a[i]*iv%mod;
14 }
15 void sat(int x){
16     len=1;while(len<=x)len<<=1;
17     for(int i=0;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0);
18 }
19 void Inv(int*a,int n){
20     static int R[S];
21     if(n==1){r[0]=qp(a[0],mod-2);return;}
22     Inv(a,n+1>>1); sat(n<<1);
23     for(int i=0;i<len;++i)R[i]=i<n?a[i]:0;
24     NTT(R);NTT(r); for(int i=0;i<len;++i)r[i]=(r[i]+r[i]-R[i]*1ll*r[i]%mod*r[i]%mod+mod)%mod;
25     NTT(r,-1); for(int i=n;i<len;++i)r[i]=0;
26 }
27 int main(){
28     scanf("%d%d",&L,&R);
29     for(int i=fac[0]=1;i<=R;++i)fac[i]=fac[i-1]*1ll*i%mod;
30     inv[R]=qp(fac[R],mod-2);
31     for(int i=R-1;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod;
32     for(int i=0;i<=R;i+=2)a[i]=i>>1&1?mod-inv[i]:inv[i];
33     Inv(a,R+1); sat(R+R);
34     for(int i=0;i<=R;++i)a[i]=0;
35     for(int i=a[0]=1;i<=R;i+=2)a[i]=i>>1&1?mod-inv[i]:inv[i];
36     NTT(r);NTT(a); for(int i=0;i<len;++i)a[i]=a[i]*1ll*r[i]%mod; NTT(a,-1);
37     for(int i=L;i<=R;++i)ans=(ans+1ll*fac[i]*a[i])%mod;
38     printf("%d\n",ans*2%mod-(L==1));
39 }
View Code

 

posted @ 2020-05-06 18:17  DeepinC  阅读(276)  评论(0编辑  收藏  举报