8月14日模拟赛

前言

\(请一定不要相信题目给的数据范围,怎么着也得多开一个1e4\)

T4 空间开小了,\(RE\).

100 ——> 60

T1 还原排列

题目描述

\(K\) 喜欢排列,比如喜欢计算循环排列的逆序对个数。

对于一个长度为 \(n\) 的数组 \(P=p_1,p_2……p_n\),我们认为它是一个长度为 \(n\) 排列,当且仅当它包含了 \([1,n]\) 中的所有正整数恰好一次。

这天,小 \(K\) 得知了一个加密排列的方法。具体地,对于一个排列 \(P\),加密后为一个长度相同的数组 \(S\)。其中,第 \(i\) 位的加密值 \(s_i\) 为满足 \(j<i\) \(&&\) \(p_j<p_i\) 的所有 \(p_j\) 的和。

\(K\) 认为这个加密方式太水了,于是随手写了一个程序解密,但是发现 \(TA\) 的程序跑了一天还没跑出来。按照套路,你能帮助小 \(K\) 通过数组 \(S\) 还原出排列 \(P\) 吗?

数据规模
对于 \(100%\) 的数据, $1 ≤ n ≤ 10_6 $

解: 树状数组倍增

这个题甚至还有写并查集的大佬(虽然我不懂

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+105;
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 n,ans[N],s[N],d[N],mp;
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int v){while(x<=n){d[x]+=v;x+=lowbit(x);}}
inline int query(int x){
	int pos=0,sum=0;
	for(int i=mp;i>=0;i--)
		if((1<<i)+pos<=n && sum+d[pos+(1<<i)]<=x) {pos+=(1<<i);sum+=d[pos];}
	return pos+1;
}
signed main(){
	n=read();mp=log2(n);
	for(int i=1;i<=n;i++) {s[i]=read();add(i,i);}
	while((1<<mp)<n)mp++;if((1<<mp)>=n)mp--;
	for(int i=n;i>=0;i--){ans[i]=query(s[i]);add(ans[i],-ans[i]);}
	for(int i=1;i<n;i++)printf("%d ",ans[i]);
	printf("%d",ans[n]);
	return 0;
} 

T2 借书

题目描述:

\(Dilhao\) 一共有 \(n\) 本教科书,每本教科书都有一个难度值,他每次出题的时候都会从其中挑两本教科书作为借鉴,如果这两本书的难度相差越大, \(Dilhao\) 出的题就会越复杂,也就是说,一道题的复杂程度等于两本书难度差的绝对值。

这次轮到 \(ldxxx\) 出题啦,他想要管 \(Dilhao\)\(m\) 本书作为参考去出题, \(Dilhao\) 想知道,如果 \(ldxxx\)\(Dilhao\) 给出的 \(m\) 本书里挑选难度相差最小的两本书出题,那么 \(ldxxx\) 出的题复杂程度最大是多少?

解:

先排序后二分答案。
\(code\):

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int N=2e5+105;
int n,m,a[N],c[N],l=1e9+7,r;
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;
}
bool C(int x){
	int sum=0,cnt=0;
	for(int i=1;i<n;i++){
		sum+=c[i];
		if(sum>=x){cnt++;sum=0;}
		if(cnt>=m-1)return 1;
	}
	return 0;
} 
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++){a[i]=read();r=max(r,a[i]);}
	sort(a+1,a+n+1);for(int i=1;i<n;i++){c[i]=a[i+1]-a[i];l=min(l,c[i]);}
	//for(int i=1;i<n;i++)printf("%d ",c[i]);
	while(l<=r){
		if(r-l==1){if(C(r))l=r;break;}
		if(C(mid))l=mid;else r=mid;
	}
	printf("%d",l);
	return 0;
}

T3 追捕

题目描述:

\(Duan2baka\):“ \(jmsyzsfq\) 天下第一蠢!”

\(jmsyzsfq\):“你说什么?!”

于是 \(Duan2baka\) 开始了逃亡的旅程,而 \(jmsyzsfq\) 也开始追捕 \(Duan2baka\) 。 他们来到了一个有 \(n\) 个节点的有向图,迅速逃跑的 \(Duan2baka\) 会首先降落在有向图的某个节点 \(T\) 上,因为怕发出声音,他会永远静止不动。

而随后跟来的 \(jmsyzsfq\) 会降落在图上随机一个节点 \(S\) 上(可以与 \(T\) 相同),并可以沿着图中的有向边随意走动。因为 \(jmsyzsfq\) 有着敏锐的嗅觉而且绝顶聪明,他一定会沿着正确的方向寻找 \(Duan2baka\)

你可以认为,如果图中存在一条合法的从 \(S\)\(T\) 的路径,那么 \(jmsyzsfq\) 一定会抓到 \(Duan2baka\) ——因此 \(jmsyzsfq\) 能否追捕到 \(Duan2baka\) 在他刚刚降落在图上的时候就已经确定了。

现在请你帮帮 \(jmsyzsfq\) ,在他降落前告诉他有多大的概率能够追捕到 \(Duan2baka\) ,并告诉他想要追到 \(Duan2baka\) 他可以降落在哪些节点上。

输入格式

输入第一行包含三个整数 \(n\)\(m\)\(opt\) ,表示图中有 \(n\) 个节点, \(m\) 条有向边; \(opt\)\(0\)\(1\),含义见输出格式所述。

输入第二行至 \(m+1\) 行每行两个整数 \(u\)\(v\) 描述了图中一条从 \(u\)\(v\) 的有向边。

输入第 \(m+2\) 行一个整数 \(T\) 表示 \(Duan2baka\) 降落的位置。

输出格式

如果输入的 \(opt\)\(0\) ,只需要输出 \(jmsyzsfq\) 能够追捕到Duan2bakaDuan2baka的概率。

如果输入的 \(opt\)\(1\) ,输出两行,第一行输出 \(jmsyzsfq\) 能够追捕到 \(Duan2baka\) 的概率;第二行按从小到大输出想要追到 \(Duan2baka\) 他可以降落的节点编号,编号间用空格隔开。

对于 \(jmsyzsfq\) 能够追捕到 \(Duan2baka\) 的概率,是一个既约分数,形如“$a / b \(”(\)a,b$为整数),使 \(gcd(a,b)=1\) ,如果 \(a=b\) ,输出\(1/1\)

\(注意,这个题的输出格式那个opt,有些人因此挂了 50 分\)

解:

先反向建图,把问题从多少点能到达目标点转化成目标点能到达哪些点。跑一边\(bfs\)即可。(如果是\(bfs\)就不用怕环了

听说缩点+dfs也可以做?(感觉代码不好写就没去研究

\(code\):

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+105;
int n,m,opt,nex[N],h[N],to[N],cnt,d[N],tot=1,x,y,T;
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 gcd(int a,int b){return b==0?a:gcd(b,a%b);}
inline void fadd(int x,int y){to[++cnt]=x;nex[cnt]=h[y];h[y]=cnt;}
void bfs(int s){
	memset(d,0,sizeof(d));
	queue<int> q;q.push(s);d[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=h[x];i;i=nex[i]){
			if(d[to[i]])continue;
			tot++;d[to[i]]=1;q.push(to[i]);
		}
	}
}
int main(){
	n=read();m=read();opt=read();
	for(int i=1;i<=m;i++){x=read();y=read();fadd(x,y);}
	T=read();bfs(T);
	int GCD=gcd(n,tot);
	printf("%d/%d\n",tot/GCD,n/GCD);
	if(opt==1){for(int i=1;i<=n;i++)if(d[i])printf("%d ",i);}
	return 0;
}

T4 空间活动

题目描述

贝茜和佩奇正在玩一款游戏,在游戏开始会生成一个有 \(n\) 个点 \(m\) 条单向边的地图,经过每条边需要花费价格为 \(H_i\) 的费用( \(H_i≤1000\) )。

但是如果两个点可以互相到达,那么这两个点之间需要花费的价格就变为 \(0\)

总共有 \(k\) 关,每一关会给你两个点 \(a\)\(b\)\(0<a,b≤n\) ),让你求从 \(a\) 走到 \(b\) 的最小花费。

大概意思就是:有一个有向图,环里的边的权值全变为0,求最短路

跑一个缩点,重新建一个有向无环图,然后直接搞最短路。

\(code\):

#include<bits/stdc++.h>
using namespace std;
const int INF=2147483647;
const int N=1e4+105;
//变量 
struct qwq{int nex,to,val;}e[N<<1];
struct pwp{int fr,t,v;}w[N<<1];
struct ovo{
	int id,va;
	friend bool operator < (ovo a,ovo b){return a.va>b.va;}
}s[N];
priority_queue<ovo> Q;
int n,m,k,x,y,z;//主函数
int num,low[N],dfn[N],q[N],h[N],tot,top,c[N];
bool vis[N<<1];//缩点
int cnt;//建图 
bool vi[N<<1];//最短路 

//快读 
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;
}
//缩点,num,low,dfn,q,vis,h,nex,to,tot,top,c
void tarjan(int x){
	low[x]=dfn[x]=++num;q[++top]=x;vis[x]=1;
	for(int i=h[x];i;i=e[i].nex){
		if(!dfn[e[i].to]){tarjan(e[i].to);low[x]=min(low[x],low[e[i].to]);}
		else if(vis[e[i].to]){low[x]=min(low[x],dfn[e[i].to]);}
	}
	if(low[x]==dfn[x]){
		tot++;
		while(q[top+1]!=x){c[q[top]]=tot;vis[q[top--]]=0;}
	}
}
//val,cnt
inline void add(int x,int y,int z){
	e[++cnt].to=y;e[cnt].val=z;
	e[cnt].nex=h[x];h[x]=cnt;
}
//最短路,vi 
void dij(int x){
	for(int i=0;i<=n;i++)s[i].id=i,s[i].va=INF;memset(vi,0,sizeof(vi));
	s[x].va=0;Q.push(s[x]);
	while(!Q.empty()){
		x=Q.top().id;Q.pop();
		if(vi[x])continue;vi[x]=1;
		for(int i=h[x];i;i=e[i].nex){
			if(vi[e[i].to])continue;
			if(s[e[i].to].va>s[x].va+e[i].val){
				s[e[i].to].va=s[x].va+e[i].val;
				Q.push(s[e[i].to]);
			}
		}
	}	
} 
int main(){//n,m,k,x,y,z
	n=read();m=read();k=read();
	for(int i=1;i<=m;i++){
		w[i].fr=read();w[i].t=read();w[i].v=read();
		add(w[i].fr,w[i].t,w[i].v);
	}
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
	memset(e,0,sizeof(e));memset(h,0,sizeof(h));cnt=0;
	for(int i=1;i<=m;i++){
		x=w[i].fr;y=w[i].t;
		if(c[x]!=c[y])add(c[x],c[y],w[i].v);
	}
	while(k--){
		x=read();y=read();
		if(c[x]==c[y]){printf("0\n");continue;}
		dij(c[x]);
		if(s[c[y]].va==INF)printf("No\n");
		else printf("%d\n",s[c[y]].va);
	}
	return 0;
}

$ The END $

posted @ 2021-08-16 15:05  Nickle-NI  阅读(47)  评论(0编辑  收藏  举报