省选模拟-Day2
关于教练拿17年联训题给我们做这件事。csp还没考这样真的好吗
整体难度中等偏上,区分度明显,然而显然时间不够
不多说,看题
十字形 cross
【问题描述】
有一个平面直角坐标系,上面有一些线段,保证这些线段至少与一条坐标轴
平行。我们需要计算出,这些线段构成的最大的十字型有多大。
称一个图形为大小为 R(R 为正整数)的十字型,当且仅当,这个图形具有
一个中心点,它存在于某一条线段上,并且由该点向上下左右延伸出的长度为 R
的线段都被已有的线段覆盖。
你可以假定:没有两条共线的线段具有公共点,没有重合的线段。
【输入格式】
从文件 cross.in 中输入数据。
第一行,一个正整数 N,代表线段的数目。
以下 N 行,每行四个整数 x1,y1,x2,y2(x1=x2 或 y1=y2),描述了一条线段。
【输出格式】
输出到文件 cross.out 中。
当不存在十字型时:输出一行“Human intelligence is really terrible”(不包括引号)。
否则:输出一行,一个整数,为最大的 R。
【样例输入 1】
1
0 0 0 1
【样例输出 1】
Human intelligence is really terrible
【样例输入 2】
3
-1 0 5 0
0 -1 0 1
2 -2 2 2
【样例输出 2】
2
【数据规模与约定】
对于 50%的数据:N≤1000。
对于 100%的数据:1≤N≤100000,所有坐标的范围在-109~109 中。
后 50%内,所有数据均为随机生成。
解
看到答案具有单调性,想到二分答案。
二分后每条线减去当前答案长度,判是否有相交线段。
线段分为平行于 轴和 轴考虑,直接上扫描线判交。
标答用的线段树维护,实际直接用平衡树即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(w>'9'||w<'0'){
if(w=='-')f=-1;
w=getchar();
}
while(w>='0'&&w<='9'){
j=(j<<3)+(j<<1)+w-'0';
w=getchar();
}
return f*j;
}
const int N=100001;
struct node1{
int l,r,pla;
}X[N],Y[N];
struct node2{
int t,pla,sum,l,r;
}p[N*5];
set<int>q;
int n,tx,ty,cnt;
inline bool cmp(node2 a,node2 b){
if(a.pla!=b.pla)return a.pla<b.pla;
return a.t<b.t;
}
bool pan(int k){
// cout<<k<<":\n";
q.clear(),cnt=0;
for(int i=1;i<=tx;i++){
int l=X[i].l+k,r=X[i].r-k;
if(l>r)continue;
// cout<<"have X-line\n";
p[++cnt].t=1,p[cnt].sum=1,p[cnt].pla=l,p[cnt].l=X[i].pla;
p[++cnt].t=1,p[cnt].sum=-1,p[cnt].pla=r+1,p[cnt].l=X[i].pla;
}
for(int i=1;i<=ty;i++){
int l=Y[i].l+k,r=Y[i].r-k;
if(l>r)continue;
p[++cnt].t=2,p[cnt].l=l,p[cnt].r=r,p[cnt].pla=Y[i].pla;
}
sort(p+1,p+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
if(p[i].t==1){
if(p[i].sum==1)q.insert(p[i].l);
else q.erase(p[i].l);
}
else{
set<int>::iterator it=q.lower_bound(p[i].l);
// if(it==q.end())printf("kk\n");
// else cout<<*it<<endl;
if(it!=q.end()&&(*it)<=p[i].r)return true;
}
}
// cout<<"-----------------\n";
return false;
}
signed main(){
// freopen("cross.in","r",stdin);
// freopen("cross.out","w",stdout);
n=rd();
for(int i=1;i<=n;i++){
int x[2],y[2];
for(int j=0;j<=1;j++)x[j]=rd(),y[j]=rd();
if(y[0]==y[1])X[++tx].l=min(x[0],x[1]),X[tx].r=max(x[0],x[1]),X[tx].pla=y[0];
else Y[++ty].l=min(y[0],y[1]),Y[ty].r=max(y[0],y[1]),Y[ty].pla=x[0];
}
int l=1,r=1e9,mid;
while(l<=r){
mid=(l+r)/2;
if(pan(mid))l=mid+1;
else r=mid-1;
}
if(!r)printf("Human intelligence is really terrible");
else printf("%d",r);
return 0;
}
集合 set
【问题描述】
小明非常喜欢数字。最近他的妈妈送给他了一个由 n 个非负整数组成的集
合。小明非常喜欢和小刚玩。他立即决定把他 n 个数字中的一部分送给小刚。为
了让游戏更加有趣,小明决定使得给她的数字集合满足如下条件:
我们用 x1 表示小明的数字集合的 xor 值,用 x2 表示小刚的数字集合的 xor
值。要使得 x1+x2 尽可能地大。假如有多种划分集合的方法使得集合满足上述条
件,小明就要让 x1 尽可能地小。
帮助小明 set 照上述方法划分集合。如果有多种合适的方法,就找出其中任
意一种方法。请注意,小明将一部分数字给了小刚之后,他可能就没有任何剩余
的数字了。反之亦然,小明也可以不给小刚任何数字。在这两种情况下,我们都
假定空集的 xor 值为 0。
【输入格式】
从文件 set.in 中输入数据。
输入的第一行包含一个整数 n,表示小明的妈妈给了他多少个数字。
第二行包含 n 个用空格隔开的数字,保证它们都是不超过 10^18 的非负整数。
【输出格式】
输出到文件 set.out 中。
输出一行,包含 n 个用空格隔开的整数,如果第 i 个数是 1,则表示小明保
留给出的第 i 个数字,如果第 i 个数是 2,则表示小明把给出的第 i 个数字给了小
刚。
【样例输入】
8
1 1 2 2 3 3 4 4
【样例输出】
1 2 1 2 2 2 1 2
【数据规模与约定】
对于 30%的数据,保证 n<=10;
对于 60%的数据,保证 n<=1000;
对于 100%的数据,保证 n<=100000。
解
复习好久没写的高消和线性基。
此题要求最大异或和,显然从高往低按位贪心。
对于所有值的异或和,如果当前第位为,当前位对答案贡献只能为。
如果当前为,可以拆作^,对答案贡献。
可以得到个异或方程,即
t表示当前数的当前位是否为1。
线性基解即可。
同时要满足 尽可能小,对于所有的异或方程,右边为1的直接给方程中最左的数划到 中,为0的不管。
代码就不放了。
通信系统 communicate
【问题描述】
在 n 个城市建立起一套通信系统。n 个城市两两之间有且仅有一条简单路径。
一个通信系统的选择方案是随机选择一段连续序号的点,方案的代价为从被选择
的点中选择任意一个点,从该点出发遍历所有被选择点,并回到出发点的总路径。
现在,你的任务就是求出通信系统代价的期望值。(对 1000000007 取模)
【输入格式】
从文件 communicate.in 中输入数据。
输入的第一行包含一个整数 n,表示城市的数量。
第 2 至 n 行每行两个整数 x,y,表示在 x 和 y 之间连一条边。
【输出格式】
输出到文件 communicate.out 中。
输出一个整数,表示期望值。
【样例输入】
10
2 1
3 2
4 3
5 3
6 5
7 1
8 2
9 3
10 6
【样例输出】
490909103
【数据规模与约定】
对于 20%的数据,n<=100
对于 40%的数据,n<=1000
对于 60%的数据,n<=5000
对于 80%的数据,n<=30000
对于 100%的数据,n<=100000
解
树上遍历选中的点?这不就是虚树吗?
对于每一种情况把虚树建出来,树上所有边权和乘2就是答案。
但是这样不太好优化,考虑每条边对答案的贡献。
对于一棵子树,将子树内节点全部标记为黑色,其余标记为白色,当选取的区间同时包含黑色和白色,答案++。
正难则反,将总选取次数减去区间只包含单色的选取次数,即为当前子树根到它的父亲这条边对答案的贡献。
可用线段树维护,启发式合并,复杂度
点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(w>'9'||w<'0'){
if(w=='-')f=-1;
w=getchar();
}
while(w>='0'&&w<='9'){
j=(j<<3)+(j<<1)+w-'0';
w=getchar();
}
return f*j;
}
const int N=100001,mod=1000000007;
struct node{
int sum,ls,rs,col_l,col_r,len_l,len_r;
}tr[N*50];
int head[N],to[N*2],fro[N*2],tail;
int root[N],siz[N],n,ans,cnt;
inline void addline(int x,int y){
to[++tail]=y;
fro[tail]=head[x];
head[x]=tail;
return ;
}
inline void whi(int l,int r){
int len=r-l+1;
tr[0].sum=1ll*len*(len-1)/2%mod;
tr[0].col_l=tr[0].col_r=0;
tr[0].len_l=tr[0].len_r=len;
return ;
}
inline int LEN(int x,int y){return y-x+1;}
void update(int u,int L,int R){
int l=tr[u].ls,r=tr[u].rs;
if(!l)whi(L,(L+R)/2);
if(!r)whi((L+R)/2+1,R);
tr[u].sum=tr[l].sum+tr[r].sum;
tr[u].sum%=mod;
if(tr[l].col_r==tr[r].col_l)tr[u].sum+=1ll*tr[l].len_r*tr[r].len_l%mod,tr[u].sum%=mod;
tr[u].col_l=tr[l].col_l;
tr[u].col_r=tr[r].col_r;
// cout<<l<<"::::"<<tr[l].len_l<<" "<<L<<" "<<R<<" "<<LEN(L,(L+R)/2)<<"||"<<tr[l].len_l<<" "<<tr[r].col_l<<endl;
if(tr[l].len_l==LEN(L,(L+R)/2)&&tr[r].col_l==tr[l].col_l)tr[u].len_l=tr[l].len_l+tr[r].len_l;
else tr[u].len_l=tr[l].len_l;
if(tr[r].len_r==LEN((L+R)/2+1,R)&&tr[r].col_r==tr[l].col_r)tr[u].len_r=tr[r].len_r+tr[l].len_r;
else tr[u].len_r=tr[r].len_r;
return ;
}
void add(int &u,int l,int r,int aim){
if(!u)u=++cnt;
if(l==r){
tr[u].col_l=tr[u].col_r=1;
tr[u].len_l=tr[u].len_r=1;
// cout<<"add:"<<l<<" "<<r<<":"<<tr[u].col_l<<" "<<tr[u].len_l<<"|"<<tr[u].col_r<<" "<<tr[u].col_r<<":"
// <<tr[u].sum<<endl;
return ;
}
int mid=(l+r)/2;
if(aim<=mid)add(tr[u].ls,l,mid,aim);
else add(tr[u].rs,mid+1,r,aim);
update(u,l,r);
// cout<<"add:"<<l<<" "<<r<<":"<<tr[u].col_l<<" "<<tr[u].len_l<<"|"<<tr[u].col_r<<" "<<tr[u].col_r<<":"
// <<tr[u].sum<<endl;
return ;
}
void merge(int &u,int v,int l,int r){
if(!v)return ;
if(l==r){
if(tr[v].col_l)u=v;
return ;
}
if(!u){
u=v;
return ;
}
int mid=(l+r)/2;
if(tr[v].ls)merge(tr[u].ls,tr[v].ls,l,mid);
if(tr[v].rs)merge(tr[u].rs,tr[v].rs,mid+1,r);
update(u,l,r);
// cout<<"merge:"<<l<<" "<<r<<":"<<tr[u].col_l<<" "<<tr[u].len_l<<"|"<<tr[u].col_r<<" "<<tr[u].col_r<<":"
// <<tr[u].sum<<endl;
return ;
}
void dfs(int u,int fa){
for(int k=head[u];k;k=fro[k]){
int x=to[k];
if(x==fa)continue;
dfs(x,u);
}
add(root[u],1,n,u);
siz[u]++;
// cout<<u<<":"<<tr[root[u]].sum<<" "<<(1ll*n*(n-1)/2-tr[root[u]].sum+mod)%mod<<endl;
if(u!=1)ans=(ans+(1ll*n*(n-1)/2-tr[root[u]].sum)+mod)%mod;
if(siz[fa]>siz[u])merge(root[fa],root[u],1,n);
else merge(root[u],root[fa],1,n),root[fa]=root[u];
siz[fa]+=siz[u];
return ;
}
int fastpow(int x,int y){
int ansn=1;
while(y){
if(y&1)ansn=1ll*ansn*x%mod;
x=1ll*x*x%mod;
y/=2;
}
return ansn;
}
signed main(){
n=rd();
for(int i=1;i<n;i++){
int x=rd(),y=rd();
addline(x,y),addline(y,x);
}
dfs(1,0);
ans=ans*2%mod;
printf("%d",1ll*ans*fastpow(1ll*n*(n+1)/2%mod,mod-2)%mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探