被签到题$min25$爆干,被水题卡常,被恶心题吓走。
其实$T3$本来应该拿$30$然而居然过掉了第一档然后搜索写挂了。
$(!(($写成了$$$((!($然后就丢了$20$分。
然而$T1$也还有$10$分的部分分没有来得及打,一个简单的自然数幂和。
于是三道题的确都有一个橘红色的分数,加起来没有人家会的一个$min23$或者一个分类讨论题得的分多。
$min25$筛到也不是不会,可是当时只学了思想并没有打板子。于是考场上并不敢花时间去现场实现。。。
于是考场上一眼秒这大概是个$min25$然后就因为不会写而丢掉了。。。
主要时间砸在$T2$上了,思路挺简单但是对$256$的内存感到不可思议,于是在那里边想边卡花了不少时间。
$T3$没怎么往正道上想,部分分跟正解并没有什么关系然后就被带偏了。
然后就没了。滚回去学$min25$板子就行了。
T1:送你一道签到题
大意:$sumlimits_{i=1}^{n}i^k sumlimits_{a_1,a_2,a_3,...,a_n} [prodlimits_{j=1}^{m} a_j =j] sigma(a_1) sigma(a_2) ... sigma(a_m) ,n le 10^{10},m le 10^9,k le 10^3$
一看这玩意是由若干积性函数拼起来的,猜测答案的$sumlimits_{i=1}^{n} f(i)$中的$f(i)$也就是关于$i$的积性函数。
然后分解后发现它的确就是积性函数。在质数的值是个低次多项式($k$次),质数的某次幂的值也可以求。(类似背包再乘组合数)
于是不难想到$min25$筛去求前缀和然后这题就没了。
算是第一次写$min25$筛所以有不少想说的。。
首先$min25$筛的第一步求$g$。在这道题里我们并不把$m$个数当作限制而是枚举最终有几个值不是$1$然后乘组合数来统计方案。
所以我们要统计的实际上是$i^k$那一项。那么也就是个低次多项式了。
$g$数组的初值是前缀和,于是在这道题里用得到自然数幂和,伯努利数或者插值任取。
然后统计分配的方案数需要设$dp[i][j]$表示$i$个位置一共选了$p^j$的情况。(积性函数只考虑每种质数处的取值所以是$p^e$的形式)
最后设$P(x)=sumlimits_{i} dp[i][x] inom{m}{i}$然后就可以在递归求解$S$的时候用了。
然后就是到底是否包含$<sqrt{n}$的质数的问题,网上两种主流写法都是可以的但是貌似把质数保留的写法方便一些。
大概要处理的东西挺多,阶乘,逆元,$g$,伯努利数,方案数$dp$,$P$,质数处的幂和。然而一步一步来看的话并不是很难理解。
多做题也许就好了吧。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Z 1111111 4 #define ll long long 5 #define mod 998244353 6 ll n,v[Z],r;int m,k,g[Z],p[Z],pc,sq,o,x[Z],s[Z],X[Z],pw[Z],fac[Z],inv[Z],iv[Z],B[Z],dp[44][44],P[44],ppw[Z]; 7 int&get(ll a){return a<=sq?x[a]:X[n/a];} 8 int C(int b,int t){return b<t||t<0?0:1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;} 9 int qp(ll b,int t,ll a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;} 10 int spow(int n,ll a=0){for(int i=0,p=n;i<=k;++i)a=(a+1ll*C(k+1,i+1)*p%mod*B[k-i])%mod,p=1ll*p*n%mod; return a*iv[k+1]%mod;} 11 int S(ll x,int y,int a=0){ 12 if(x<=1||p[y]>x)return 0; 13 for(int i=y,pe=1;1ll*p[i]*p[i]<=x&&i<=pc;++i) 14 for(ll e=1,p0=p[i],p1=p0*p0,rt=ppw[i]; p1<=x ; ++e) 15 a=(a+1ll*P[e]*rt%mod*S(x/p0,i+1)+1ll*P[e+1]*rt%mod*ppw[i])%mod, p0*=p[i],p1*=p[i],rt=rt*ppw[i]%mod; 16 return (a+1ll*P[1]*(g[get(x)]-pw[y-1]+mod))%mod; 17 } 18 int main(){ 19 cin>>n>>m>>k;sq=sqrt(n); 20 for(int i=fac[0]=1;i<Z;++i)fac[i]=1ll*fac[i-1]*i%mod; 21 inv[Z-1]=qp(fac[Z-1],mod-2); 22 for(int i=Z-2;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod,iv[i+1]=1ll*fac[i]*inv[i+1]%mod; 23 for(int i=B[0]=1;i<k+3;++i)for(int j=0;j<i;++j) 24 B[i]=(B[i]-1ll*B[j]*C(i+1,j)%mod*iv[i+1]%mod+mod)%mod; B[1]++; 25 26 for(int i=dp[0][0]=1;i<40;++i)for(int j=i-1;j<40;++j)for(int z=39;z>j;--z) 27 dp[i][z]=(dp[i][z]+dp[i-1][j]*(z-j+1ll))%mod; 28 for(int j=1;j<40;++j)for(int i=1,C=m;i<=j;++i) 29 P[j]=(P[j]+1ll*dp[i][j]*C)%mod,C=1ll*C*(m-i)%mod*iv[i+1]%mod; 30 31 for(int i=2;i<=sq;++i){ 32 if(!s[i])p[++pc]=i,ppw[pc]=pw[pc]=s[i]=qp(i,k); 33 for(int j=1;i*p[j]<=sq;++j){s[i*p[j]]=1ll*s[i]*s[p[j]]%mod;if(i%p[j]==0)break;} 34 } 35 for(int i=1;i<=sq;++i) s[i]=(s[i-1]+s[i])%mod; 36 for(int i=1;i<=pc;++i) pw[i]=(pw[i]+pw[i-1])%mod; 37 for(ll i=1,N,l;N=n/i,i<=n;i=l+1) l=n/N,v[get(N)=++o]=N,g[o]=N<=sq?s[N]:spow(N%mod)-1; 38 for(int i=1;i<=pc;++i)for(int j=1;j<=o&&1ll*p[i]*p[i]<=v[j];++j) 39 g[j]=(g[j]-1ll*ppw[i]*(g[get(v[j]/p[i])]-pw[i-1])%mod+mod)%mod; 40 cout<<S(n,1)+1<<endl; 41 }
T2:神渀
大意:给定一个$012$数列以及一个权值序列,强制在线求每个点为右端点的子区间中,满足$012$个数互不相同的区间的最大异或和。$n le 3 imes 10^5$
首先这个限制非常奇怪,区间出现次数互不相同。
然而被不少题吊起来锤的我们总算会了点$trick$,直接差分。问题转变成差分也要互不相同。
互不相同不好处理,但是相同貌似就好处理很多。
最大异或和于是也不难想到建$01trie$。
于是我们只需要维护$trie$的每个节点上,每种相同的值出现了多少次就好了,然后就可以根据$size$判断是否可以往那个方向走。
然而我蠢了,为什么非得建一个$trie$然后上面维护那么多信息?时空常数太大。
对于每种值都建一棵$trie$就好了。
然而还是会被卡空间,又有一个神奇的$trick$.我们设$a=cnt0-cnt1,b=cnt1-cnt2,c=cnt0-cnt2$
那么我们实际上是对于$a,b,c,ab,bc,ac,abc$这$7$种值都建$trie$
然而实际上如果$ab$相同,那么就是$cnt1-cnt0,cnt2-cnt1$相同,那么就是$cnt2-cnt1+cnt1-cnt0=cnt2-cnt0=c$相同。
那么就是$abc$相同。所以说后四个$trie$是完全一样的可以压成一个,于是就卡过去了。
另外加一些优化,就是压一个儿子,或者压链。都能卡进$256MiB$的原限制。但是代码吗,就比较恶心了。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 300005ll 4 #define Z 40000005 5 map<int,int>rt[3];map<long long,int>RT; 6 int p[S],A[S],n,c[2][Z],op,la,pc,cc[3],sz[Z],R; 7 void insert(int&p,int w,int x=29){ 8 if(!p)p=++pc; sz[p]++; if(x<0)return; 9 insert(c[w&1<<x?1:0][p],w,x-1); 10 } 11 int ask(int p,int p1,int p2,int p3,int p4,int w,int x=29){ 12 if(x<0)return 0; 13 int o=w&1<<x?0:1; 14 if(sz[c[o][p]]!=sz[c[o][p1]]+sz[c[o][p2]]+sz[c[o][p3]]-2*sz[c[o][p4]])return ask(c[o][p],c[o][p1],c[o][p2],c[o][p3],c[o][p4],w,x-1)|1<<x; 15 o^=1;return ask(c[o][p],c[o][p1],c[o][p2],c[o][p3],c[o][p4],w,x-1); 16 } 17 int main(){ 18 cin>>n>>op; 19 for(int i=1;i<=n;++i)scanf("%d",&p[i]); 20 for(int i=1;i<=n;++i)scanf("%d",&A[i]); 21 insert(R,0);insert(rt[0][0],0);insert(rt[1][0],0);insert(rt[2][0],0);insert(RT[0],0); 22 for(int i=1;i<=n;++i){ 23 if(op)A[i]^=la,(p[i]^=la)%=3;cc[p[i]]++;A[i]^=A[i-1]; 24 int a=cc[1]-cc[0],b=cc[2]-cc[1],c=cc[2]-cc[0]; 25 la=(sz[rt[0][a]]+sz[rt[1][b]]+sz[rt[2][c]]-2*sz[RT[a*S+b]]==i)?0:ask(1,rt[0][a],rt[1][b],rt[2][c],RT[a*S+b],A[i]); 26 printf("%d ",la); insert(R,A[i]); insert(rt[0][a],A[i]); insert(rt[1][b],A[i]); insert(rt[2][c],A[i]); insert(RT[a*S+b],A[i]); 27 } 28 }
T3:外挂
大意:求$n imes m$的$01$矩阵中每个点,有多少种满足:所有的$1$可以被两个大小为$x imes y$的矩形完全覆盖。$n,m le 60$
我也不知道为啥没想到。
首先为了不重不漏,我们缩小包围圈$nm$保证四个边界上一定有人。这样的话只需要两层枚举边框大小就行。
然后问题转化为:边框上一定有人且能被两个特定矩形覆盖的方案数。
发现最优的覆盖方案一定是放在左上角,右下角。或者放在右上角,左下角。
于是状压$6$维:是否有点已经在$4$个边界上,是否有点出现在了两种覆盖方法之外。
然后就没了,逐个点讨论填不填的影响就行了。时间复杂度$O(2^6n^2m^2)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 998244353 4 int ans,n,m,x,y,pw[3666],dp[2][1<<6]; 5 void add(int&a,int b){a+=b;if(a>=mod)a-=mod;} 6 int cal(int n,int m){ 7 int L=0,N=1,X=n-x+1,Y=m-y+1; 8 for(int s=0;s<1<<6;++s)dp[L][s]=0;dp[L][0]=1; 9 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ 10 for(int s=0;s<1<<6;++s)dp[N][s]=0; 11 for(int s=0;s<1<<6;++s)add(dp[N][s|(i==1)<<5|(i==n)<<4|(j==1)<<3|(j==m)<<2|(!(i<=x&&j<=y)&&!(i>=X&&j>=Y))<<1|(!(i>=X&&j<=y)&&!(i<=x&&j>=Y))],dp[L][s]),add(dp[N][s],dp[L][s]); 12 L^=1;N^=1; 13 }return(0ll+dp[L][62]+dp[L][61]+dp[L][60])%mod; 14 } 15 int main(){ 16 cin>>n>>m>>x>>y; 17 for(int i=pw[0]=1;i<=n*m;++i)pw[i]=(pw[i-1]<<1)%mod; 18 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)ans=(ans+cal(i,j)*(n-i+1ll)%mod*(m-j+1))%mod; 19 cout<<1+ans<<endl; 20 }