22.8.28 总结

A

求最小 n 使得 n2k 的倍数且 n 不为 k 的倍数。

k=p1q1p2q2....
则使 n=p1q12p2q22...

code
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long int64;
const int64 N=1e6+10;
int64 k,s,f=1;
int main() {
	scanf("%lld",&k); s=k;
	for(int64 i=2; i<=N; i++) {
		int p=0;
		while(k%i==0) {p++; k/=i;}
		f*=pow(i,(p+1)/2);
	}
	if(f%s!=0) printf("%lld\n",f);
	else printf("-1\n");
	return 0;
}

B

有一个 a 数列其中 1ai9。若相邻两个数的互质,则可以交换。
交换若干,问可以得到多少不同数列。

我们先不考虑 1,5,7,因为它们可以插入到数列任意位置。
然后就剩下了 2,3,4,6,8,9,
其中 6 是不能与其他数交换了,所以用 6 给数列分段。
每个数列里有 2,4,83,9,分为两组,每组之间相对顺序不变。
2,4,8p 个, 3,9q 个。
这组答案为 Cp+qq, 每组答案乘起来即可。

最后考虑 1,5,7,设它们出现次数为 x,y,z.
相似的,答案乘上 Cnx×Cnxy×Cnxyz.

code
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long int64;
const int64 N=1e5+10,mod=998244353;
int64 n,a[N],frac[N],cnt[10],p,q,ans=1;
int64 exgcd(int64 a,int64 b,int64 &x,int64 &y) {
	if(b==0) {x=1; y=0; return a;}
	int64 g=exgcd(b,a%b,x,y),z=x;
	x=y; y=z-(a/b)*y;
	return g;
}
int64 C(int64 n,int64 m) {
	if(n==0||m==0) return 1;
	int64 res=frac[n];
	int64 div1,div2,y;
	exgcd(frac[m],mod,div1,y); div1=(div1%mod+mod)%mod;
	exgcd(frac[n-m],mod,div2,y); div2=(div2%mod+mod)%mod;
	res=res*div1%mod;
	res=res*div2%mod;
	return res;
}
signed main() {
	scanf("%lld",&n);
	frac[0]=1;
	for(int64 i=1; i<=n; i++) frac[i]=frac[i-1]*i%mod;
	for(int64 i=1; i<=n+1; i++) {
		if(i<=n) scanf("%lld",&a[i]);
		if(a[i]==6||i==n+1) {
			ans=ans*C(p+q,p)%mod;
			p=q=0;
		}
		else if(a[i]%2==0) p++;
		else if(a[i]%3==0) q++;
		cnt[a[i]]++;
	}
	ans=ans*C(n,cnt[1])%mod;
	ans=ans*C(n-cnt[1],cnt[5])%mod;
	ans=ans*C(n-cnt[1]-cnt[5],cnt[7])%mod;
	printf("%lld\n",ans);
	return 0;
}

C

有一个 a 数列,现在要想让前 i 个数相等。
你可以让一个数 +1 花费代价 p, 1 花费代价 q.

可以证明,最后所有数相等与其中的一个数。
还可以证明,按照大小排序,每一次决策变化只会移动一个数。
第一次决策为第一个数。

code
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<set>
using namespace std;
typedef long long int64;
const int64 N=1e5+10,inf=1e16;
int64 n,f,g,a[N],b[N],v[N];
int64 c1[N],c2[N],lastans=-1;
set<int64> s; 
void modify(int64 c[],int64 p,int64 x) {
	for(; p<N; p+=p&-p) c[p]+=x;
}
int64 query(int64 c[],int64 p) {
	int64 res=0;
	for(; p; p-=p&-p) res+=c[p];
	return res;
}
int64 calc(int64 p) {
	int64 res=0;
	int64 num0=query(c2,n),num=query(c2,p);
	int64 sum0=query(c1,n),sum=query(c1,p);
	res+=f*(num*b[p]-sum);
	res+=g*(sum0-sum-(num0-num)*b[p]);
	return res;
}
int64 solve() {
	if(lastans==-1) {
		lastans=*s.begin();
		return 0;
	}
	set<int64> ::iterator it1,it2,it3;
	int64 ans1=inf,ans2=inf,ans3=inf,ans0;
	it1=it2=it3=s.lower_bound(lastans);
	ans1=calc(*it1);
	if(it2!=s.begin()) it2--;
	ans2=calc(*it2);
	if(it3!=--s.end()) it3++;
	ans3=calc(*it3);
	ans0=min(ans1,min(ans2,ans3));
	if(ans0==ans1) {
		lastans=*it1;
	} else if(ans0==ans2) {
		lastans=*it2;
	} else lastans=*it3;
	return ans0;
}
signed main() {
//	freopen("data.in","r",stdin); 
//	freopen("data.out","w",stdout);
	scanf("%lld%lld%lld",&n,&f,&g);
	for(int64 i=1; i<=n; i++) {
		scanf("%lld",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	for(int64 i=1; i<=n; i++)
		a[i]=lower_bound(b+1,b+n+1,a[i])-b;
	for(int64 i=1; i<=n; i++) {
		s.insert(a[i]);
		modify(c1,a[i],b[a[i]]);
		modify(c2,a[i],1);
		printf("%lld\n",solve());
	}
	return 0;
}

D

在一棵树上任意简单路径的权值 2d , d 为长度。
q 次询问,每次询问经过 x,y 的所有路径权值和。

考虑把一条路径对答案的贡献分成三部分,x 的子树内(y 为根时),y 的子树内(x 为根
时),xy 之间的路径。那么相同部分可以相加,最后乘起来就行了。对于前两部分可以
换根或者预处理讨论,第三部分需要快速的求 Lca

posted @   s1monG  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示