近期模拟赛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}\) 的最后一步,肯定是合并两个集合,因为每次合并的都是相邻的,所以合并的是两个区间的并集
那么考虑环怎么做:将长度倍长,然后考虑每个长度为 \(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\) .
输出格式
一行一个整数表示答案。