近期模拟赛2

9月8日前言

兄弟,你不能板子加一个题目背景你就不会了。

T2 【2018.8雅礼8.12T2】b

题目

描述

给定 \(n\) 个正整数序列 \(a_1,a_2,…,a_n\),每个序列长度为 \(m\)

选择至少 \(1\) 个序列,在每个被选择的序列中选择一个元素,求出所有被选择的元素的 \(gcd\)

求所有方案的结果之和,答案对 \(1e9+7\) 取模。两种方案不同,当且仅当存在至少一个元素,在一种方案中被选择,在另一种中没有。

输入格式

第一行,两个正整数 \(n,m\)

接下来 \(n\) 行,每行 \(m\) 个正整数,第 \(i\) 行代表序列 \(ai\)

输出格式

一行,一个整数,代表答案对 \(1e9+7\) 取模的结果。

思路

这里记 \(a\) 的最大值为 \(x\)

将问题转化为“对 \(i∈[1,1e5]\) ,求多少种选择方案使得 \(gcd=i\)

继续转化为“对 \(i∈[1,1e5]\) ,求多少种选择方案使得 \(i|gcd\) "。这里可以 \(O(x)\) 或者直接暴力 \(O(xlnx)\) 容斥回去。

等价于 “对 \(i∈[1,1e5]\) ,求多少种选择方案使得选的所有数均为\(i\) 的倍数” 。

\(O(n(m+xlnx))\) 处理处第 \(i\) 行有多少个数是 \(j\) 的倍数,记为
\(cnt_{i,j}\)
那么,共有 \(\prod ^{n} _{i=1} (cnt_{i,j}+1) -1\) 种方案,使得选的所有数均为 \(j\) 的倍数。这一步为 \(O(nm)\)

code


T3 【2018.8雅礼8.15T1】朝圣

题目

描述

作为一名公爵,保持虔诚是十分重要的。因此你决定去罗马给教皇送礼朝圣。

朝圣路途遥远而艰辛,具体来说,在你的领地到罗马之间有 \(n\) 座城市,其中你的领地标号为 \(1\),罗马标号为 \(n\),城市之间有 \(m\) 条单向道路,这些道路不会形成环。

为了送礼朝圣,你需要准备一些宝物。每座城市都有一个宝物(包括起点和终点),这些宝物是两两不同的,每个宝物有一个重量,第 \(i\) 座城的宝物重量为 \(w_i\)

你将从自己的城市出发,沿着道路走到罗马去,每到一座城市,你都可以选择是否拿起当地的宝物,但是你携带的宝物总重不能超过 \(L\),于是你想知道你有多少种朝圣的方案,两种方案被认为是不同的,当且仅当路线不同或携带的宝物不同。

输入格式

第一行三个正整数 \(n,m,L\)

第二行 \(n\) 个数,第 \(i\) 个数表示 \(w_i\)

接下来 \(m\) 行,每行两个数 \(x,y\) 。表示一条从 \(x\)\(y\) 的单向道路。

输出格式

一个数表示答案,对 \(998244353\) 取模。

思路

\(f[i][j]\) 表示在 \(i\) 号点,总重量为 \(j\)

code


T4 【雅礼2019.10.10pmT1】合并集合

题目

描述

\(n\) 个集合,第 \(i\) 个集合记为 \(S_i\),集合按环状排列,即第 \(i\) 个集合右边是第 \(i+1\) 个集合,第 \(n\) 个集合右边是第 \(1\) 个集合。

一开始每个集合里只有一个数,每次你可以选择两个相邻的集合 \(S,T\),然后合并成 \(S∪T\),之后你获得收益 \(|S|∗|T|\),其中 \(|S|\) 表示集合 \(S\) 的元素个数。

你需要一直进行以上的操作直到只剩一个集合为止,求能获得的最大的收益之和。

输入格式

第一行一个正整数 \(n\)

第二行 \(n\) 个正整数 \(a\),表示一开始有 \(S_i=\{ai\}\)

输出格式

输出一个非负整数表示最大的收益之和。

思路

考虑问题的弱化版,假设不是环,而是一条链

\(f[i][j]\) 表示将 \(S_{i...j}\) 合并成一个后最大的收益之和

\(g[i][j]=|S_{i..j}|\) ,也就是将 \(S_{i...j}\) 合并后的集合大小

考虑转移,考虑合并 \(S_{i...j}\) 的最后一步,肯定是合并两个集合,因为每次合并的都是相邻的,所以合并的是两个区间的并集

\[f[i][j]=MAX_{k=i...j-1}\{f[i][j]+f[k+1][j]+g[i][k]*g[k+1][j]\} \]

那么考虑环怎么做:将长度倍长,然后考虑每个长度为 \(n\) 的区间的答案即可

code


9月6日前言

哈哈哈不知道说什么……


T1 [2018.8长郡集训day1]都市

题目

描述

塔立于都市,攀登上塔,能够到达更远的地方。但是上塔,需要破解谜题。仍然有\(𝑁\)个数,但并不给你,而是给了你 \(N\times \frac{N-1}{2}\) 个数,代表它们两两的和。那么,这 \(N\) 个数是多少呢?

输入格式

一行一个整数 \(N\)

接下来一行 \(N\times \frac{N-1}{2}\) 个数,代表两两之和。

输出格式

第一行一个整数 \(𝑠\) 代表解的个数。

接下来 \(s\)行,每行 \(N\) 个数代表一组解,数从小到大排列。解的顺序按照字典序 从大到小 排列.

思路

code

#include<bits/stdc++.h>
using namespace std;
const int N=405,M=1e5+105;
int n,m,ans[N][N],res[N],cnt,a[M];
bool v[M];
void jc(int num){
	memset(v,0,sizeof(v));
	if((a[1]+a[2]+a[num])%2==1) return ;
	res[1]=(a[1]+a[2]+a[num])/2-a[num];
	res[2]=a[1]-res[1];res[3]=a[2]-res[1];
	v[1]=1;v[2]=1;v[num]=1;
	int j=3;
	for(int i=4;i<=n;i++){
		while(v[j] && j<=m) j++;		
		if(j>m) return ;
		res[i]=a[j]-res[1];v[j]=1;
		for(int k=2;k<i;k++){			
			if(res[k]>res[i]) return ;
			int x=res[k]+res[i];int y=lower_bound(a+1,a+m+1,x)-a;			
			if(a[y]!=x) return ;
			int Y=y;
			while(Y && a[Y]==a[y])  Y--;
			Y++;
			while(Y<=m && a[Y]==a[y] && v[Y]) Y++;			
			if(a[Y]!=a[y] || v[Y]) return ;
			y=Y;v[y]=1;
		}
	}
	cnt++;
	for(int i=1;i<=n;i++) ans[cnt][i]=res[i];
}
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
int main(){
	n=read();m=n*(n-1)/2;
	for(int i=1;i<=m;i++)a[i]=read();
	sort(a+1,a+1+m);
	for(int i=3;i<=m;){		
		jc(i);int j=i;
		while(a[j]==a[i] && j<=m) j++;
		i=j;
	}
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++){
		for(int j=1;j<n;j++) printf("%d ",ans[i][j]);
		printf("%d\n",ans[i][n]);
	}
	return 0;
}

T3 [2018.8雅礼集训8.6]Prime

题目

描述

输入格式

一行三个整数 \(L, R, K\) .

输出格式

一行一个整数表示答案。

思路

code

posted @ 2021-09-10 20:43  Nickle-NI  阅读(101)  评论(0编辑  收藏  举报