【题解】CF13 合集

前言:

  1. 本人不会 LaTeX……请见谅
  2. 码风奇特,不喜勿喷哈
  3. 题面翻译取自 luogu,本蒟蒻也会安置原题链接
  4. 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
  5. AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
  6. 有写错的地方欢迎各位神犇指正
  7. 本套题共 5 道(水题+计算几何+简单 dp+计算几何+板子题),预计阅读 + 理解时间小于 30min(或许手模推理过程时间大于 2h?)

正片开始!

CF13A

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

进制转换+gcd

推理过程:

  • 三句话秒了(这句也算)
  • 按题意进制转换,并统计数字和 ans
  • n2 求最大公约数,约分输出答案即可

细节处理:

代码:

点击查看代码
#include<iostream>
using namespace std;
int f[12];
inline int gcd(int a,int b){
	if(b==0){
		return a;
	}
	return gcd(b,a%b);
}
int main(){
	f[0]=1;
	for(int i=1;i<=10;i++){
		f[i]=f[i-1]*2;
	}
	int n;
	cin>>n;
	int ans=0;
	for(int i=2;i<=n-1;i++){
		int tmp=n;
		while(tmp){
			ans+=(tmp%i);
			tmp/=i;
		}
	}
	int p=gcd(ans,n-2);
	cout<<ans/p<<'/'<<(n-2)/p<<endl;
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF13B

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:蓝题(个人感觉 CF 老题难度评级虚高)

简单的计算几何!

推理过程:

  • 提炼三条性质
  1. 其中的两条线段有共同的端点(我们称它们为 $ s1,s2 s3 $ 的端点分别在这两条不同的线段上
  2. s1s2 的夹角 α 必须满足 0<απ2
  3. s3 截得的另外两条线段的较小长度与较大长度的比值必须 14
  • 第一条性质是很好做(分 12 种情况讨论)的,为了方便处理,通过交换线段与端点使得 s1s2 分别为第一和第二条线段,且 s1.as2.a 相同(对应到代码区即那一坨 if else

  • 第二条性质是更好做的,构造结点、向量,直接余弦定理控制夹角即可

  • 第三条性质是最好做的,我们假设较长的线段是 a,较短线段是 b

  • 由题意,得:ba14

  • a+b5b

  • 显然有

  • 判定方式:计算 x,y 的最小值和最大值,与 s3 的端点进行比较

细节处理:

  • 建议判断函数拆开写,函数操作越简单越优

  • 结点、向量使用结构体封装一下捏!

  • 听说此题卡精度……

代码:

知周所众,计算几何的代码没有可读性

点击查看代码
#include<iostream> 
#include<cstdio>
#define int long long
using namespace std;
inline bool _inbound(int a,int b,int c){
	return a<=b&&b<=c;
}
inline bool inbound(int a,int b,int c){
	return _inbound(a,b,c)||_inbound(c,b,a);
}
struct node{
	int x,y;
	node(int x=0,int y=0):x(x),y(y){}
	inline void input(){
		scanf("%lld%lld",&x,&y);
	}
	friend bool operator == (const node &a,const node &b){
		return a.x==b.x&&a.y==b.y;
	}
	friend node operator + (const node &a,const node &b){
		return node(a.x+b.x,a.y+b.y);
	}
	friend node operator - (const node &a,const node &b){
		return node(a.x-b.x,a.y-b.y);
	}
	friend int operator * (const node &a,const node &b){
		return a.x*b.x+a.y*b.y;
	}
	friend int operator & (const node &a,const node &b){
		return a.x*b.y-a.y*b.x;
	}
};
struct Segment{
	node a,b;
	inline void input(){
		a.input();
		b.input();
	}
}s1,s2,s3;
inline bool in_segment(const Segment &s,const node &a){
	if(inbound(s.a.x,a.x,s.b.x)&&inbound(s.a.y,a.y,s.b.y)){
		if(((s.a-a)&(s.b-a))==0){
			return true;
		}else{
			return false;
		}
	}
	return false;
}
inline void solve(){
	s1.input();
	s2.input();
	s3.input();
	if(s1.a==s2.a){
		swap(s1,s1);
		swap(s2,s2);
		swap(s1.a,s1.a);
		swap(s2.a,s2.a);
	}else if(s1.a==s2.b){
		swap(s1,s1);
		swap(s2,s2);
		swap(s1.a,s1.a);
		swap(s2.b,s2.a);
	}else if(s1.b==s2.a){
		swap(s1,s1);
		swap(s2,s2);
		swap(s1.b,s1.a);
		swap(s2.a,s2.a);
	}else if(s1.b==s2.b){
		swap(s1,s1);
		swap(s2,s2);
		swap(s1.b,s1.a);
		swap(s2.b,s2.a);
	}else if(s1.a==s3.a){
		swap(s1,s1);
		swap(s3,s2);
		swap(s1.a,s1.a);
		swap(s2.a,s2.a);
	}else if(s1.a==s3.b){
		swap(s1,s1);
		swap(s3,s2);
		swap(s1.a,s1.a);
		swap(s2.b,s2.a);
	}else if(s1.b==s3.a){
		swap(s1,s1);
		swap(s3,s2);
		swap(s1.b,s1.a);
		swap(s2.a,s2.a);
	}else if(s1.b==s3.b){
		swap(s1,s1);
		swap(s3,s2);
		swap(s1.b,s1.a);
		swap(s2.b,s2.a);
	}else if(s2.a==s3.a){
		swap(s2,s1);
		swap(s3,s2);
		swap(s1.a,s1.a);
		swap(s2.a,s2.a);
	}else if(s2.a==s3.b){
		swap(s2,s1);
		swap(s3,s2);
		swap(s1.a,s1.a);
		swap(s2.b,s2.a);
	}else if(s2.b==s3.a){
		swap(s2,s1);
		swap(s3,s2);
		swap(s1.b,s1.a);
		swap(s2.a,s2.a);
	}else if(s2.b==s3.b){
		swap(s2,s1);
		swap(s3,s2);
		swap(s1.b,s1.a);
		swap(s2.b,s2.a);
	}else{
		printf("NO\n");
		return;
	}
	if(in_segment(s1,s3.a)){
		swap(s3.a,s3.a);
	}else if(in_segment(s1,s3.b)){
		swap(s3.b,s3.a);
	}else{
		printf("NO\n");
		return;
	}
	if(!in_segment(s2,s3.b)){
		printf("NO\n");
		return;
	}
	int cos_angle=(s1.b-s1.a)*(s2.b-s2.a);
	if(cos_angle<0){
		printf("NO\n");
		return;
	}
	int x_mn, x_mx;
	int y_mn, y_mx;
	x_mn=s1.a.x*4+s1.b.x;
	x_mx=s1.a.x+s1.b.x*4;
	y_mn=s1.a.y*4+s1.b.y;
	y_mx=s1.a.y+s1.b.y*4;
	if(!(inbound(x_mn,s3.a.x*5,x_mx)&&inbound(y_mn,s3.a.y*5,y_mx))){
		printf("NO\n");
		return;
	}
	x_mn=s2.a.x*4+s2.b.x;
	x_mx=s2.a.x+s2.b.x*4;
	y_mn=s2.a.y*4+s2.b.y;
	y_mx=s2.a.y+s2.b.y*4;
	if(!(inbound(x_mn,s3.b.x*5,x_mx)&&inbound(y_mn,s3.b.y*5,y_mx))){
		printf("NO\n");
		return;
	}
	printf("YES\n");
	return;
}
signed main(){
	int T;
	scanf("%lld",&T);
	while(T--){
		solve();
	}
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF13C

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:蓝题(个人感觉上位黄题)

考察 dp 及空间优化

题面好评!

推理过程:

  • 嗯哼,先上一个小性质:存在一种最优方案,每个位置上的数,是原序列中的数

  • 感性的证明:

  1. 花费最小,说明尽可能让每个数动的波动小。能不动就不动,如果必须要动的话,变成上一个位置上的数就可以了。这里假设上一个位置的数已经确定

  2. So?所以一个数要么是自己,要么是上一个位置上的数。而上一个数怎么来的呢?很明显,也是这样,要么不动,要么是上上个位置的数

  3. 以此类推……结论得证!

  • 所以完全可以拷贝一下原数组并排序……就称它为 b 好了!

  • 老套路:钦定一个 fi,j,表示前 i 个数已经单调不降且第 i 位的数是 bj,令 mni,j 表示 min{fi,1,fi,2,...,fi,j}

  • 方程酱紫:fi,j=min{mni,j+|aibj|}

  • 云落交了一发,MLE

  • 这题卡空间……

  • 诶? i 那一维似乎可以压掉……

  • 直接钦定 dp0/1,j 表示 mni1/i,j

  • 直接做做完了!

细节处理:

  • 预处理!初始化!

  • 不开祖宗见 long long

代码:

点击查看代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define int long long
using namespace std;
const int maxn=5e4+10;
int n,a[maxn];
int b[maxn],dp[2][maxn];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
		cin>>a[i];
	}
    memcpy(b,a,sizeof(a));
    sort(b+1,b+n+1);
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n;i++){
		dp[0][i]=0;
	}
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
        	dp[1][j]=min(dp[1][j-1],dp[0][j]+abs(a[i]-b[j]));
		}
        swap(dp[1],dp[0]);
    }
	int ans=9e18;
    for(int i=1;i<=n;i++){
		ans=min(ans,dp[0][i]);
	}
    cout<<ans<<endl;
    return 0;
}

--------------------云落的分割线--------------------

CF13D

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:蓝题?(个人感觉上位黄)

枚举+计算几何

推理过程:

  • 三句话秒了(这句也算)

  • O(n3) 枚举三个点

  • O(1) 向量外积判断

细节处理:

  • 还是那句话:结点、向量建议结构体封装

  • 千万不要开 long long,不然你会 AC

代码:

难得简单的有可读性的计算几何代码~

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=512;
int n,m;
struct node{
	int x,y;
	friend bool operator < (const node &a,const node &b){
		return a.y<b.y;
	}
}r[maxn],b[maxn];
int ans,dp[maxn][maxn];
inline bool CHECK(int x1,int y1,int x2,int y2){
	return x1*y2>x2*y1;
}
inline bool check(node a,node b,node c){
	if(c.y<a.y||c.y>=b.y){
		return false;
	}
	return CHECK(c.x-a.x,c.y-a.y,b.x-a.x,b.y-a.y);
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&r[i].x,&r[i].y);
	}
	for(int i=1;i<=m;i++){
		scanf("%lld%lld",&b[i].x,&b[i].y);
	}
	sort(r+1,r+n+1);
	sort(b+1,b+m+1);
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			for(int k=1;k<=m;k++){
				dp[i][j]+=check(r[i],r[j],b[k]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			for(int k=j+1;k<=n;k++){
				ans+=(dp[i][j]+dp[j][k]==dp[i][k]);
			}
		}	
	}
	printf("%lld\n",ans);
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF13E

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:紫题

Splay 板子题变式

事先声明:云落的 Splay 写法令人作呕,请不要翻阅代码区

题解区许多分块做的,强大的 O(nn) 算法

推理过程:

  • 支持若干种操作
  1. 插入

  2. 删除

  3. 分裂

  4. 查询前驱

  • 脑子不够(想不到分块),数据结构来凑

细节处理:

  • 卡时间捏!较快输入输出方式!

  • 一个让云落虚空调试许久的细节问题:

if(x+i>n){
	a[i]=n+1;
}else{
	a[i]=x+i;
}

代码:

备花!备花!

点击查看代码
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e6+10;
int a[maxn];
struct Splay_tree{
	int fa,son[2];
	int sz;
	int rev;
}tr[maxn];
inline bool check_root(int pos){
	return tr[tr[pos].fa].son[0]!=pos&&tr[tr[pos].fa].son[1]!=pos;
}
inline int get(int pos,int fa){
	return tr[fa].son[1]==pos;
}
inline void connect(int pos,int fa,int son){
	tr[fa].son[son]=pos;
	tr[pos].fa=fa;
	return;
}
inline void pushup(int pos){
	tr[pos].sz=tr[tr[pos].son[0]].sz+tr[tr[pos].son[1]].sz+1;
	return;
}
inline void pushdown(int pos){
	if(!tr[pos].rev){
		return;
	}
	swap(tr[pos].son[0],tr[pos].son[1]);
	tr[tr[pos].son[0]].rev^=1;
	tr[tr[pos].son[1]].rev^=1;
	tr[pos].rev=0;
	return;
}
inline void pushall(int pos){
	if(!check_root(pos)){
		pushall(tr[pos].fa);
	}
	pushdown(pos);
	return;
}
inline void rotate(int pos){
	int fa=tr[pos].fa,gf=tr[fa].fa;
	int t1=get(pos,fa),t2=get(fa,gf);
	connect(tr[pos].son[t1^1],fa,t1);
	connect(fa,pos,t1^1);
	tr[pos].fa=gf;
	if(tr[gf].son[t2]==fa){
		tr[gf].son[t2]=pos;
	}
	pushup(fa);
	pushup(pos);
	return;
}
inline void splay(int pos){
	pushall(pos);
	while(!check_root(pos)){
		int fa=tr[pos].fa,gf=tr[fa].fa;
		if(!check_root(fa)){
			get(pos,fa)^get(fa,gf)?rotate(pos):rotate(fa);
		}			
		rotate(pos);
	}
	return;
}
inline void access(int pos){
	int son=0;
	while(pos){
		splay(pos);
		tr[pos].son[1]=son;
		pushup(pos);
		son=pos;
		pos=tr[pos].fa;
	}
	return;
}
inline void rk(int pos){
	access(pos);
	splay(pos);
	tr[pos].rev^=1;
	return;
}
inline void insert(int x,int y){
	rk(x);
	tr[x].fa=y;
	return;
}
inline void del(int x,int y){
	rk(x);
	access(y);
	splay(y);
	tr[y].son[0]=0;
	tr[x].fa=0;
	pushup(y);
	return;
}
inline void split(int x,int y){
	rk(x);
	access(y);
	splay(y);
	return;
}
inline int pre(int pos){
	pos=tr[pos].son[0];
	pushdown(pos);
	while(tr[pos].son[1]){
		pos=tr[pos].son[1];
		pushdown(pos);
	}
	splay(pos);
	return pos;
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n+1;i++){
		tr[i].sz=1;
	}
	int x,y;
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		if(x+i>n){
			a[i]=n+1;
		}else{
			a[i]=x+i;
		}
		insert(i,a[i]);
	}
	while(m--){
		int opt;
		scanf("%d",&opt);
		if(opt==1){
			scanf("%d",&x);
			split(x,n+1);
			printf("%d %d\n",pre(n+1),tr[n+1].sz-1);
		}else{
			scanf("%d%d",&x,&y);
			del(x,a[x]);
			a[x]=x+y>n?n+1:x+y;
			insert(x,a[x]);
		}
	}
	return 0;
}

完结撒花!

posted @   sunxuhetai  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示