【Day2】【纪中OJ】2019.1.24大型被虐C组模拟赛(游记+题解)


游记

Morning

【Before 8:00】
早餐喝了杯豆浆真开心 (大雾)
【Before 12:00】
C组题目

题目 做法
【东莞市选2008】GCD与LCM 数论
【东莞市选2008】幻灯片 暴力、离散化/扫描线(线段树)
【东莞市选2008】导弹 匈牙利算法、最短路(Floyd)、二分答案/网络流
【东莞市选2008】医院 贪心

**OJ!卡BUG害我有一堆编译错误,害我两题爆0
考试得分:100+0+62.5+0=162.5
实际得分:100+25+62.5+62.5=250
蒟蒻+各位大佬排名

姓名 名次 分数
lyf 1 250
prj 2 225
cnh 3 212.5
5 162.5

(查成绩大法好)
我好弱啊
【Before 2:00】
去饭堂取得很早,看到好多大佬腐手机,自己也跟着腐了一把。打开三崩子,刷了一波每日
中午睡得巨香

Afternoon

【Before 5:00】
码了一会儿T1题解,听大佬讲课。
授课名单

题号 评价 授课人
T1 讲得乱七八糟,还被小六大佬砸场子了 蒟蒻本人
T2 大佬强无敌,两个大佬在上面讲一些蜜汁算法(?) 被拉过来的组织授课大佬+lzc小六大佬强
T3 有理有据,令人信服 prj
T4 水分导论 cnh+lyf

难度:第一题<第四题<第三题<第二题

Evening

【Before 10:00】
跑去303听了逆元(一脸懵逼)
后面又讲了一遍T3疯狂玩凤姐梗


纪中C组T1-GCD与LCM题解

----------------------一条WA的分界线-------------------------------
【题目描述】给出某两个整数a和b(a<=b)的最大公约数GCD和最小公倍数LCM,请找出满足的a和b,使得b-a的值最小。
【输入】输入数据只有一行,包括两个整数GCD 和LCM。输入保证至少存在一组解。
【输出】输出包含一个整数,为最小的b-a的值。
【样例输入】6 36
【样例输出】6
【数据范围限制】对于50%的数据,1<=a<=b<=103,对于100%的数据,1<=a<=b<=910;
-----------------------一条TLE的分界线----------------------------

【难度系数】★★☆☆☆
【核心算法】数论
-----------------------一条MLE的分界线-------------------------------
【思路】由大佬lyf的紧密推算可知样例的两个数分别为12、18,将这两个数用短除法进行运算,草稿如下图:

就是:

①我们已知由这些E数列乘起来的最大公因数,以及由E数列和C、D的乘积最小公倍数,所以将最小公倍数除以最大公因数就可以得到C和D的乘积了。又得A=C最大公因数,B=D最大公因数,题意为尽量让B-A最小(就是让B与A尽量接近),所以可得问题为“已知C和D的乘积,使C和D最接近”
②通过大佬prj的推算可知C与D互质,问题升级为“已知C和D的乘积,使C和D最接近并互质”
③关于对“已知C和D的乘积,使C和D最接近”问题的做法,举例:假设CD为6,而在6的因数1、2、3、6中,我们只要知道前一半数1、2,自然就可以得出后一半数3、6。
④求B-A=>D
最大公因数-C*最大公因数=>(D-C)*最大公因数
⑤没有了喵~~~~~
-----------------------一条RE的分界线-------------------------------
【代码】

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
ll gcd,lcm,l; 
bool pd(ll x,ll y){//判断两个数是否互质(对应步骤②) 
	int z;
	while (z=x%y){
		x=y;
		y=z;
	}
	if (abs(y)==1) return true;
	else return false;
}
int main(){
	cin>>gcd>>lcm;
	lcm/=gcd;// lcm变为C和D的乘积 
	for (ll i=1;i<=sqrt(lcm);++i)//枚举因数(对应步骤③)
	  if (lcm%i==0&&pd(lcm/i,i)==true) l=lcm/i-i;//C对应i,D对应lcm/i,l记录D-C的差值(对应步骤①) 
	cout<<l*gcd<<endl;//最后将(D-C)*最大公因数gcd并输出(对应步骤④) 
	return 0;
}

大佬传送门
某大佬prj的题解


纪中C组T2幻灯片题解

题目描述
给出一张无向的完全图(任意两点之间都有一条边的图)G=(V,E),它可以表示出某一块大陆的地图:每个顶点表示一座城市,每条边代表连接的两个城市间的距离,该大陆任两个城市都是直接连通的。另外在这个大陆上有两个特殊的国家,我们称为A国与B国,其中A国有N个城市,B国有M个城市。这里A国相对于B国来说是一个大国(我们有N>=M),而且它最近发明了一种新型武器:响尾蛇导弹(A Crotalid Missile),这种武器威力十分巨大,以至于每枚导弹都可以摧毁任意一座城市。A国总统在战略安排上要求A国管辖的每个城市都配备一枚这种响尾蛇导弹。B国窃取到了这个情报,B国总统当然不能坐以待毙,他感觉受到了强大的威胁,于是要求他们的科学家们尽快研制出一个导弹防御系统来抵御将来可能遭受的攻击。当然这个防御系统必须是可靠且有效的,因此在制造系统之前B国的科学家们必须首先考虑清楚该系统的反应速度如何确定。所以作为B国最聪明科学家之一的你,必须尽快算出A国要摧毁B国所有城市至少需要的时间是多少。

输入
输入第一行为一个整数K(2<=K<=100),表示这块大陆的顶点数。接下来K行,每行包含K个整数,描述了城市的连接情况。这个K*K的矩阵中,matrix[i][j]表示城市i到城市j的距离,这也是导弹由城市i到城市j间的飞行时间。这里有:matrix[i][j]=matrix[j][i],matrix[i][i]=0,1<=matrix[i][j]<=100。接下来一行为整数N,1<=N<=K,为A国的城市数。下面一行N个整数,列出A国管辖的城市编号. 再下来一行为整数M,1<=M<=N,为B国的城市数。下面一行M个整数,列出B国管辖的城市编号。A国与B国管辖的所有城市编号均不相同。

输出
输出文件只有一行,为导弹摧毁B国所有城市至少所需要的时间。

样例输入
3
0 2 1
2 0 10
1 10 0
1
2
1
3

样例输出
3
-----------------------一条WA的分界线-------------------------------
【难度系数】★★★★★
【核心算法】暴力、离散化
【思路】
①这道题正常来说是二维数组模拟计数器,但由于X1,Y1,X2,Y2<=10^9的不正常数据,只能用离散化做。
②对于离散化,先要给x轴y轴排序去重,然后要找出边界坐标对应离散后的坐标数组的下标。
③在离散后的棋盘坐标上标记染色并统计
④有些大佬说要加减0.5,感觉不需要这么精密啊
⑤没有了喵
-----------------------一条RE的分界线-------------------------------
代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=105;   //最大矩阵数
const int maxcolor=100005;  //最大颜色编号
struct Rec{               //矩阵的存储结构
    int x1,y1,x2,y2,c;
}r[maxn];
int x[maxn*2],xn;     //x坐标数值的数组,不同的x坐标总数
int y[maxn*2],yn;     //y坐标数值的数组,不同的y坐标总数
int col[maxn*2][maxn*2];  //各个离散棋盘块的颜色
char mark[maxcolor];     //标记某颜色编号是否存在
int main()
{
    int n, ans;   //矩阵数,答案
    int xl,xr,yl,yr;  //离散后的四个边界下标
    int i,j,k;
    cin>>n;
    for(i=0;i<n;i++){
        scanf("%d%d%d%d%d",&r[i].x1,&r[i].y1,&r[i].x2,&r[i].y2,&r[i].c);
        //将坐标加入对应的数组中
        x[i*2]=r[i].x1, x[i*2+1]=r[i].x2;
        y[i*2]=r[i].y1, y[i*2+1]=r[i].y2;
    }//对x坐标数组排序并去重
    sort(x,x+n+n);
    for(xn=i=1;i<n+n;i++)
        if(x[i]!=x[i-1]) x[xn++]=x[i];//对y坐标数组排序并去重
    sort(y,y+n+n);
    for(yn=i=1;i<n+n;i++)
        if(y[i]!=y[i-1]) y[yn++]=y[i];
    memset(col,0,sizeof(col));
    for(i=0;i<n;i++){//找出边界坐标对应离散后的坐标数组的下标
        for(j=0;j<xn;j++){
            if(x[j]==r[i].x1) xl=j;  //找到x坐标的左边界下标
            if(x[j]==r[i].x2) xr=j;  //找到x坐标的右边界下标
        }
        for(j=0;j<yn;j++){
            if(y[j]==r[i].y1) yl=j;  //找到y坐标的左边界下标
            if(y[j]==r[i].y2) yr=j;  //找到y坐标的右边界下标
        }//在离散后的棋盘坐标上染色
        for(j=xl;j<xr;j++)
            for(k=yl;k<yr;k++)
                col[j][k]+=r[i].c;
    }//标记各种存在的颜色
    memset(mark,0,sizeof(mark));
    for(i=0;i<xn;i++)
        for(j=0;j<yn;j++)
            mark[col[i][j]]=1;
    for(ans=0,i=1;i<=maxcolor;i++) ans+=mark[i];//统计所有存在的颜色
    printf("%d\n",ans);//输出答案
    return 0;
}

大佬传送门
某大佬lyf的题解


纪中C组T3导弹题解

【题目描述】
给出一张无向的完全图(任意两点之间都有一条边的图)G=(V,E),它可以表示出某一块大陆的地图:每个顶点表示一座城市,每条边代表连接的两个城市间的距离,该大陆任两个城市都是直接连通的。另外在这个大陆上有两个特殊的国家,我们称为A国与B国,其中A国有N个城市,B国有M个城市这里A国相对于B国来说是一个大国(我们有N>=M),而且它最近发明了一种新型武器:响尾蛇导弹(A Crotalid Missile),这种武器威力十分巨大,以至于每枚导弹都可以摧毁任意一座城市。A国总统在战略安排上要求A国管辖的每个城市都配备一枚这种响尾蛇导弹。B国窃取到了这个情报,B国总统当然不能坐以待毙,他感觉受到了强大的威胁,于是要求他们的科学家们尽快研制出一个导弹防御系统来抵御将来可能遭受的攻击。当然这个防御系统必须是可靠且有效的,因此在制造系统之前B国的科学家们必须首先考虑清楚该系统的反应速度如何确定。所以作为B国最聪明科学家之一的你,必须尽快算出A国要摧毁B国所有城市至少需要的时间是多少。
【输入】
输入第一行为一个整数K(2<=K<=100),表示这块大陆的顶点数。接下来K行,每行包含K个整数,描述了城市的连接情况。这个K*K的矩阵中,matrix[i][j]表示城市i到城市j的距离,这也是导弹由城市i到城市j间的飞行时间。这里有:matrix[i][j]=matrix[j][i],matrix[i][i]=0,1<=matrix[i][j]<=100。
接下来一行为整数N,1<=N<=K,为A国的城市数。下面一行N个整数,列出A国管辖的城市编号。再下来一行为整数M,1<=M<=N,为B国的城市数。下面一行M个整数,列出B国管辖的城市编号。A国与B国管辖的所有城市编号均不相同。
【输出】
输出文件只有一行,为导弹摧毁B国所有城市至少所需要的时间。
【样例输入】
3
0 2 1
2 0 10
1 10 0
1
2
1
3
【样例输出】
3
-------------------------一条WA的分界线----------------------------------
【难度系数】★★★★☆
【核心算法】匈牙利算法、最短路(Floyd)、二分答案
-----------------------一条MLE的分界线-------------------------------
【思路】
①观察数据N<=100,三重循环不会爆,可以选择最短路→Floyd算法;
②当得知所有城市的最短路径时,下一步就是要A、B城市互相匹配,所以需要用到二分图匹配——匈牙利算法,如果所有B城市都被匹配到了就证明当前值成立
③看到此题要求“最小中的最大”,“最小”指对于一A城市与离它最近的B城市的距离,“最大”意为等最远的A城市到达B城,故求最大值,以保证最长时间。考虑二分答案。
④枚举二分答案时如果二分图不匹配就说明答案在mid+1≈r中,如果匹配就说明mid成立,但为了求最优解进一步枚举l≈mid-1
⑤没有了喵
-----------------------一条TLE的分界线-------------------------------
【算法分析】
匈牙利算法
我们可以把每一个城市看成人

首先,我们先按升序连线

当连到大佬LYF时,我们发现LYF的凤姐被大佬PRJ抢了。这时,我们先看大佬PRJ还可以连微笑狗,可微笑狗被大佬CNH连了,我们可以发现大佬CNH还可以连如花,就把如花给大佬CNH,把微笑狗腾出来给大佬PRJ,把凤姐腾出来给大佬LYF。

最后把蒟蒻ddk与工口小萝莉连接。

此时,所有右边的女生(?)都已经连完了,所以我们要用二分答案,继续在l≈mid-1中找最优值,如果用图表示则可能边会减少
-----------------------一条RE的分界线-------------------------------
【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxx=105;
struct lenc{
	int x,y,z;
}c[maxx*maxx];
bool f[maxx];
int N,n,m,ans,t,sum,e[maxx][maxx],a[maxx],b[maxx],link[maxx],ls[maxx];
void addl(int x,int y){
	c[++t].x=x;
	c[t].y=y;
	c[t].z=ls[x];
	ls[x]=t;
}
bool Find(int x){//匈牙利算法 
	for (int i=ls[x];i;i=c[i].z){
		if (!f[c[i].y]){//如果当前B城市已经被匹配了 
			int k=link[c[i].y];//k为本来匹配当前B城市的A城市 
			link[c[i].y]=x;
			f[c[i].y]=true;
			if (!k||Find(k)) return true;//如果k城市还能匹配其他城市就把这个B城市腾出来给当前A城市 
			link[c[i].y]=k;
		}
	}
	return false;
}
bool check(int x){
	sum=0;
	t=0;
	memset(link,0,sizeof(link));
	memset(ls,0,sizeof(ls));
	for (int i=1;i<=n;++i)
	  for (int j=1;j<=m;++j)
	    if (e[a[i]][b[j]]<=x) addl(i,j);//建边  
	for (int i=1;i<=n;++i){
		memset(f,0,sizeof(f));
		if (Find(i)) sum++;//开始用匈牙利算法匹配每一A城市,如果匹配成功sum(计数器)++ 
	}
	return sum==m;//判断是否所有B城市都被匹配过 
}
int main(){
	cin>>N;
	for (int i=1;i<=N;++i)
	  for (int j=1;j<=N;++j)
	  	cin>>e[i][j];
	cin>>n;
	for (int i=1;i<=n;++i) cin>>a[i];
	cin>>m;
	for (int i=1;i<=m;++i) cin>>b[i];
	for(int k=1;k<=N;k++)
      for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
            if(e[i][j]>e[i][k]+e[k][j]&&i!=j&&i!=k&&j!=k)
                 e[i][j]=e[i][k]+e[k][j];//Floyd算法 
    int l=1,r=1e6;//二分答案 
    while(l<=r){
    	int mid=(l+r)/2;
    	if (check(mid)) r=mid-1;//如果mid成立就找最优解 
    	               else l=mid+1;//如果不成立就往后找 
	}
	cout<<l<<endl;
}


大佬传送门
某大佬wyc的题解


纪中C组T4医院题解

【题目描述】给出一个有向图G=(V,E),它表示某地一些城市的连接关系。由于要提供医疗服务,政府需要在某些城市中建设一些医院。但出于某些因素的考虑,作出如下限制:一个城市至多只能有一间医院,同时,两个相邻的城市也只能有一间医院。注意城市i与城市j相邻当且仅当G中存在一条有向边<i,j>或<j,i>。因此有些城市可能就不能建立医院了,这样,没有医院的城市的人们就会让有医院的城市派出医生为他们看病。当然人们都愿意选择离他们最近城市的医生过来,但如果离他们最近的城市都很远的话,病人们就会很不满意,因为这需要承担很多让医生过来的路费。这个不满意度是这样计算的:
S[i] = ( 离城市i最近的医院到城市i所经过的边数 / 3 ) * U
这里的i为某个没有医院的城市,U为某个常数,”/”为整除符号。你的任务是制订一套建设医院的方案,使得满足上述条件的约束下,所有城市的不满意度值之和最小。你要注意你的方案必须能让医院覆盖到所有的城市,即每个城市都至少有一个医院能出发到达。
【输入】输入第一行为两个整数N和M,分别表示城市数与边的数量。1<=N<=100,0<=M<=10000。接下来M行,每行两个整数X和Y,1<=X,Y<=N,X≠Y,表示存在一条X到Y的有向边。最后一行为一个整数U,为定义不满意度值中使用到的那个常数。
【输出】输出包含三行,第一行为你找到的最小的不满意度值之和,第二行为你的方案建立的医院数量H,第三行有H个整数,为建立医院所在的城市,按城市编号由小到大排序。这样的方案可能不唯一,在保证不满意度值之和最小的情况下,输出任意一种均可。
【样例输入】
4 3
2 1
4 3
3 2
10
【样例输出】
0
2
2 4
-----------------------一条MLE的分界线------------------------------
【难度系数】★★☆☆☆

【核心算法】贪心
【思路】
你以为第四题一定是最难的?你以为第四题是有向的树形DP?
②记录入度和出度,把出度为0的城市放医院并递归查找入度,然后更新离它隔3个距离的城市的心情值
③再扫一次,把心情值不为0的城市放医院,并更新离它隔3个距离的城市的心情值
④因为把心情值不为0的程序都放了医院,所以直接输出0
⑤没有了喵
-----------------------一条TLE的分界线-------------------------------
代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=105;
int n,m,U,ans,bad[maxn],rd[maxn],cd[maxn][maxn];
bool f[maxn];
void Bad(int x,int h){//更新心情值
	if (h>3) return;
	bad[x]=min(bad[x],0);
	for (int i=1;i<=cd[x][0];++i)
	  Bad(cd[x][i],h+1);
	return;
}
int main(){
	memset(bad,0x7f,sizeof(bad));
	cin>>n>>m;
	for (int i=1;i<=m;++i){
		int x,y;
		cin>>x>>y;
		rd[y]++;
		cd[x][0]++;
		cd[x][cd[x][0]]=y;//记录入度和出度
	}
	cin>>U;
	cout<<"0"<<endl;
	for (int i=1;i<=n;++i)
		if (rd[i]==0){//在出度为0的点安医院
			ans++;
	        f[i]=true;
	        Bad(i,0);
	    }
	for (int i=1;i<=n;++i)
		if (bad[i]>3){//在有心情值的点安医院
		    ans++;
	        f[i]=true;
	        Bad(i,0);
		}
	 cout<<ans<<endl;
	 for (int i=1;i<=n;++i)
	    if (f[i]) cout<<i<<" ";	
	return 0;
}

【相关链接】

震惊!东莞三学生中午piaochang 玩手机被抓!
男人看了会哭泣,女人看了会流泪!lyf大佬不参加NOIP的解释竟然是不屑于NOIP,怕浪费时间——“用那点时间还不如上几回厕所呢”By-lyf
这是一个男默女泪的故事,大佬lyf和大佬cnh联手打造骗分导论,有理有据,令人信服。
不转不是地球人!蒟蒻ddk竟然研发出大佬prj幻想的“见不了光的东西”。
XC凤姐 狂三美如画

猜你喜欢

转载自blog.csdn.net/qq_44618728/article/details/86631592
今日推荐