• 2022710 #10 CF1644F & CF643F & CF1588F


    第十篇了呢!

    感冒了,今天就做一些简单的题目吧。

    028 CF1644F Basis

    之前 edu 没做出来的题。

    观察可知,我们选出来的基一定是去掉最后一段之后所有段的 \(\gcd=1\) 的串,我们直接对其计数:

    枚举最大的 \(\gcd\) 进行容斥,容易发现容斥系数为 \(\mu(k)\):(注意为避免对空集求 \(\gcd\),我们需要忽略只有一段的情况)

    \[\sum_{k=1}^{n}\mu(k)(\sum_{i=1}^k{\lceil\frac{n}{k}\rceil\brace i}-1) \]

    而求第二类斯特林数前缀和单项可以线性,具体地,我们列出卷积的式子:

    \[{n\brace k}=\frac{1}{k!}\sum_{i=0}^k{k\choose i}(-1)^{k-i}i^n=\sum_{i=0}^k\frac{(-1)^{k-i}}{(k-i)!}\cdot\frac{i^n}{i!} \]

    枚举第一维对第二维做前缀和即可,注意 \(i^n\) 需要线性筛。

    复杂度 \(O(n\log n)\)

    #include<stdio.h>
    const int maxn=200005,mod=998244353;
    int n,m,ans,ps;
    int c[maxn],p[maxn],miu[maxn],mul[maxn],rec[maxn],A[maxn],B[maxn],nfac[maxn],inv[maxn];
    void sieve(int n){
    	c[1]=miu[1]=inv[1]=nfac[0]=nfac[1]=1;
    	for(int i=2;i<=n;i++){
    		if(c[i]==0)
    			p[++ps]=i,miu[i]=-1;
    		rec[i]=ps,inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod,nfac[i]=1ll*nfac[i-1]*inv[i]%mod;
    		for(int j=1;j<=ps&&i*p[j]<=n;j++){
    			c[i*p[j]]=1;
    			if(i%p[j]==0)
    				break;
    			miu[i*p[j]]=-miu[i];
    		}
    	}
    }
    int ksm(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1)
    			res=1ll*res*a%mod;
    		a=1ll*a*a%mod,b>>=1;
    	}
    	return res;
    }
    int calc(int n,int k){
    	if(k>n)
    		k=n;
    	mul[1]=1;
    	for(int i=2;i<=k;i++){
    		if(c[i]==0)
    			mul[i]=ksm(i,n);
    		for(int j=1;j<=rec[i]&&i*p[j]<=n;j++){
    			mul[i*p[j]]=1ll*mul[i]*mul[p[j]]%mod;
    			if(i%p[j]==0)
    				break;
    		}
    	}
    	int res=0;
    	for(int i=1;i<=k;i++)
    		B[i]=(B[i-1]+1ll*mul[i]*nfac[i]%mod)%mod;
    	for(int i=0;i<=k;i++)
    		res=(res+1ll*A[i]*B[k-i])%mod;
    	return res;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	if(n==1||m==1){
    		puts("1");
    		return 0;
    	}
    	sieve(n);
    	for(int i=0;i<=n;i++)
    		A[i]=1ll*((i&1)? mod-1:1)*nfac[i]%mod;
    	for(int i=1;i<=n;i++)
    		if(miu[i])
    			ans=(ans+1ll*(miu[i]+mod)*(calc((n+i-1)/i,m)-1+mod))%mod;
    	printf("%d\n",ans);
    	return 0;
    }
    

    029 CF643F Bears and Juice

    比较神奇的题。

    我们考虑熊能表示出的状态数是多少:

    \[\sum_{i=0}^{\min(p,n-1)}{n\choose i}t^i \]

    表示枚举有几只熊睡觉,如果睡了是在哪一天睡的。

    可以构造策略使得其恰好能辨认出第 \(1,2,\cdots,\sum_{i=0}^{\min(p,n-1)}{n\choose i}t^i\) 这些酒桶。

    假设是第 \(k\) 个桶是酒,我们只需让哪些醉了的熊恰好在它们对应的天喝这桶,其他的不喝即可。

    于是我们要对于 \(t\in[1,q]\) 快速计算上式,我们可以 \(O(pq)\) 枚举,对于所有 \(i\leqslant\min(p,n-1)\) 预处理 \(n\choose i\) 即可 \(O(1)\) 计算。

    复杂度 \(O(pq)\)

    #include<stdio.h>
    const int maxn=205;
    int n,p,q;
    int v[maxn];
    unsigned int ans;
    unsigned int C[maxn];
    int gcd(int a,int b){
    	return b==0? a:gcd(b,a%b);
    }
    int main(){
    	scanf("%d%d%d",&n,&p,&q);
    	for(int i=0;i<=p&&i<=n-1;i++){
    		for(int j=1;j<=i;j++)
    			v[j]=n-j+1;
    		for(int j=1;j<=i;j++){
    			int w=j;
    			for(int k=1;k<=i;k++){
    				int g=gcd(w,v[k]);
    				w/=g,v[k]/=g;
    			}
    		}
    		C[i]=1;
    		for(int j=1;j<=i;j++)
    			C[i]*=v[j];
    	}
    	for(int i=1;i<=q;i++){
    		unsigned int res=0,mul=1;
    		for(int j=0;j<=p&&j<=n-1;j++,mul*=i)
    			res+=C[j]*mul;
    		ans^=i*res;
    	}
    	printf("%u\n",ans);
    	return 0;
    }
    

    030 CF1588F Jumping Through the Array

    2e5 8s,考虑操作分块。

    一开始以为是基环树。。。

    先考虑没有 3 操作的情况,询问的时候枚举这个块内的修改,可以 \(O(1)\) 计算这个环内的区间内结点数量,走完一个操作块就重新计算一下权值。

    有 3 操作时,我们不方便直接维护每个环,也不方便重新计算权值,我们考虑能不能暴力处理这件事。

    实际上是可以的,我们每次提取出操作影响到的点作为关键点,把没有修改过的点挂在关键点上面,我们维护这样一个 \(O(\sqrt n)\) 的图暴力修改查询就好了。注意我们要对于每个环维护一个二维前缀和状物,发现两维都可以离散化到 \(O(\sqrt n)\),暴力处理即可。

    复杂度 \(O((n+q)\sqrt q)\)

    头痛,懒得写严格根号了。。。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=200005;
    int n,q,ps;
    int p[maxn],qo[maxn],qx[maxn],qy[maxn],bel[maxn],pos[maxn];
    long long a[maxn],sum[maxn],lazy[maxn];
    vector<int>v[maxn];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&p[i]),bel[i]=-1;
    	scanf("%d",&q);
    	for(int L=1,R;L<=q;L=R+1){
    		R=min(R+500,q),ps=0;
    		for(int i=L;i<=R;i++){
    			scanf("%d%d%d",&qo[i],&qx[i],&qy[i]);
    			if(qo[i]==2)
    				bel[qx[i]]=qx[i];
    			if(qo[i]==3)
    				bel[qx[i]]=qx[i],bel[qy[i]]=qy[i];
    		}
    		for(int i=1;i<=n;i++)
    			if(bel[i]==-1){
    				int j,k,f=1;
    				for(j=p[i];j!=i&&bel[j]==-1;j=p[j]);
    				for(k=i;(k!=i&&bel[k]==-1)||f;k=p[k])
    					bel[k]=j==i? 0:bel[j],f=0;
    			}
    		for(int i=1;i<=n;i++){
    			sum[i]=sum[i-1]+a[i];
    			if(bel[i]==i)
    				pos[++ps]=i;
    			if(bel[i]>0)
    				v[bel[i]].push_back(i);
    		}
    		for(int i=L;i<=R;i++){
    			int o=qo[i],x=qx[i],y=qy[i];
    			if(o==1){
    				long long res=sum[y]-sum[x-1];
    				for(int j=1;j<=ps;j++)
    					res+=1ll*(upper_bound(v[pos[j]].begin(),v[pos[j]].end(),y)-lower_bound(v[pos[j]].begin(),v[pos[j]].end(),x))*lazy[pos[j]];
    				printf("%lld\n",res);
    			}
    			if(o==2){
    				int flg=1;
    				for(int i=x;i!=x||flg;i=bel[p[i]])
    					lazy[i]+=y,flg=0;
    			}
    			if(o==3)
    				swap(p[x],p[y]);
    		}
    		for(int i=1;i<=n;i++)
    			if(bel[i]>0)
    				a[i]+=lazy[bel[i]];
    		for(int i=1;i<=n;i++)
    			bel[i]=-1,lazy[i]=0,v[i].clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    RocketMQ延迟消息的代码实战及原理分析
    如何做技术选型?Sentinel 还是 Hystrix?
    什么是服务熔断?
    降级-熔断-限流-傻傻分不清楚
    java-分布式-降级 熔断 限流
    java-分布式-分布式事务
    常用限流算法的应用场景和实现原理
    使用Redis作为分布式锁的一些注意点
    ansible {{}}引用变量,变量中嵌套变量如何表示
    shell获得java进程号跟进程对应的线程号
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/16462941.html
Copyright © 2020-2023  润新知