【题解】CF13 合集
前言:
- 本人不会 LaTeX……请见谅
- 码风奇特,不喜勿喷哈
- 题面翻译取自 luogu,本蒟蒻也会安置原题链接
- 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
- AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
- 有写错的地方欢迎各位神犇指正
- 本套题共 5 道(水题+计算几何+简单 dp+计算几何+板子题),预计阅读 + 理解时间小于 30min(或许手模推理过程时间大于 2h?)
正片开始!
CF13A
题面(可从下方链接跳转看原题题面):
序言 & 结论:
进制转换+gcd
推理过程:
- 三句话秒了(这句也算)
- 按题意进制转换,并统计数字和
- 与
求最大公约数,约分输出答案即可
细节处理:
代码:
点击查看代码
#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 老题难度评级虚高)
简单的计算几何!
推理过程:
- 提炼三条性质
- 其中的两条线段有共同的端点(我们称它们为 $ s1,s2
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 及空间优化
题面好评!
推理过程:
-
嗯哼,先上一个小性质:存在一种最优方案,每个位置上的数,是原序列中的数
-
感性的证明:
-
花费最小,说明尽可能让每个数动的波动小。能不动就不动,如果必须要动的话,变成上一个位置上的数就可以了。这里假设上一个位置的数已经确定
-
So?所以一个数要么是自己,要么是上一个位置上的数。而上一个数怎么来的呢?很明显,也是这样,要么不动,要么是上上个位置的数
-
以此类推……结论得证!
-
所以完全可以拷贝一下原数组并排序……就称它为
好了! -
老套路:钦定一个
,表示前 个数已经单调不降且第 位的数是 ,令 表示 -
方程酱紫:
-
云落交了一发,MLE
-
这题卡空间……
-
诶?
那一维似乎可以压掉…… -
直接钦定
表示 -
直接做做完了!
细节处理:
-
预处理!初始化!
-
不开祖宗见 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
题面(可从下方链接跳转看原题题面):
序言 & 结论:
难度:蓝题?(个人感觉上位黄)
枚举+计算几何
推理过程:
-
三句话秒了(这句也算)
-
枚举三个点 -
向量外积判断
细节处理:
-
还是那句话:结点、向量建议结构体封装
-
千万不要开 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 写法令人作呕,请不要翻阅代码区
题解区许多分块做的,强大的
推理过程:
- 支持若干种操作
-
插入
-
删除
-
分裂
-
查询前驱
- 脑子不够(
想不到分块),数据结构来凑
细节处理:
-
卡时间捏!较快输入输出方式!
-
一个让云落虚空调试许久的细节问题:
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;
}
完结撒花!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具