【OI】CodeGolf1

前言

省流:3.1KB->382 字符。

CodeGolf,即用尽一切手段得到最短解,允许在可接受的范围内牺牲一定的效率。本文限制编程语言为 C++14,环境以某 OJ 为准。

至于标题后面有个 1,我也不知道会不会有 2。本文纯闲的没事干。

代码框的标题中的数字是本地直接数字符数量数的,实际交到 OJ 上会多出几 B。

Tips:代码超出代码框时,代码框下面有个深蓝色的滚动条可以拖动。

正文

题目

题目
$T$ 组数据,每次给定 $n$ 个区间 $[l_i,r_i]$,任意两个区间 $p,q$ 都有一条连边,边权为两区间交集大小。求该图最小生成树。$1\le T\le 10^5,1\le n,\sum n\le 2\times 10^6,1\le l_i\lt r_i\le 10^9$。

由于是 CodeGolf,重点不在如何想到正解,这里只大概过一下思路:

考虑最小生成树,每次选边权最小的边加边。一个点能连出的边权最小的边只能是与这三种连:右端点最小的,左端点最大的,区间长度最小的(也就是这三个点是确定的)。然后每个点贪心的连边即可,其中三个点要特殊处理,具体见代码。

3.1KB 的代码是模拟赛时写的一坨。

最普通的代码

可读性应该还可以吧……

770B
#include<bits/stdc++.h>
using namespace std;
struct S{int l,r;};
int main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
    while(T--){
        int n;cin>>n;
        vector<S>a(n);for(auto&[l,r]:a)cin>>l>>r;
        int x=max_element(a.begin(),a.end(),[&](S p,S q){return p.l<q.l;})-a.begin(),
            y=min_element(a.begin(),a.end(),[&](S p,S q){return p.r<q.r;})-a.begin(),
            z=min_element(a.begin(),a.end(),[&](S p,S q){return p.r-p.l<q.r-q.l;})-a.begin();
        auto cap=[&](int i,int j){return i==j?0:max(0,min(a[i].r,a[j].r)-max(a[i].l,a[j].l));};
        long long o1=cap(x,y),o2=cap(x,z),o3=cap(y,z),ans=o1+o2+o3-max({o1,o2,o3});
        for(int i=0;i<n;i++)ans+=min({cap(i,x),cap(i,y),cap(i,z)});
        cout<<ans<<'\n';
    }
	return 0;
}

初步压缩

STL 使用迭代器还需要 .begin().end(),所以换成数组。结构体还得用 .,拆成两个数组 $l$ 和 $r$。发现 max_element 等函数内的比较函数太长了,再额外记录一个数组 $s$ 表示区间长度,这样就不用传比较函数了。lambda 表达式也变成普通函数。

然后可以把所有变量在一起定义,包括循环变量 $i$,把所有变量名都变成单字符的,$o_1,o_2,o_3$ 没必要。不过 ans 要开 long long,这个暂时单独定义。

发现 cin.tie(0)->sync_with_stdio(0); 太长了,但是本题输入量过大,不关同步的话就要用 scanf,经测试,把 $l,r$ 的输入换成 scanf 是最优的(不 TLE 且代码最短)。

510B
#include<bits/stdc++.h>
using namespace std;
int T,n,l[2000005],r[2000005],s[2000005],x,y,z,i;
int f(int i,int j){return i==j?0:max(0,min(r[i],r[j])-max(l[i],l[j]));}
int main(){
    cin>>T;
    while(T--){
        cin>>n;for(i=0;i<n;++i)scanf("%d%d",&l[i],&r[i]);
        x=max_element(l,l+n)-l,y=min_element(r,r+n)-r,z=min_element(s,s+n)-s;
        long long D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)});
        for(i=0;i<n;++i)D+=min({f(i,x),f(i,y),f(i,z)});
        cout<<D<<'\n';
    }
	return 0;
}

小寄巧

首先对于函数 $f$,要 int 定义还要传参数还要 return,还是太长了,直接换成 #definef(i,j) 后的空格可以省略),不过注意要加括号,否则会有运算优先级的问题:

C++
#define f(i,j)(i==j?max(0,0:min(r[i],r[j])-max(l[i],l[j])))

然后我们发现这几个 _element 实在是太长了,不如在输入的循环里算好,这样 $s$ 也不需要了。不过用 if 的话太长了,所以要用三目运算。还需要把 $x,y,z$ 初始化成 0。

C++
for(x=y=z=i=0;i<n;++i)scanf("%d%d",&l[i],&r[i]),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;

然后我们发现定义数组时的两个 2000005 太长了,直接换成 1<<21。$D$ 也应该定义在主函数外,但还是暂时单独定义。由于 long long 太长了,所以我们用 long。完整代码如下:

466B
#include<bits/stdc++.h>
using namespace std;
int T,n,l[1<<21],r[1<<21],x,y,z,i;long D;
#define f(i,j)(i==j?max(0,min(r[i],r[j])-max(l[i],l[j])):0)
int main(){
    cin>>T;
    while(T--){
        cin>>n;for(x=y=z=i=0;i<n;++i)scanf("%d%d",&l[i],&r[i]),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;
        D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)});
        for(i=0;i<n;++i)D+=min({f(i,x),f(i,y),f(i,z)});
        cout<<D<<'\n';
    }
	return 0;
}

更进一步

!?!百尺竿头!?!

注意到 $f$ 有如下等价但更短的写法:

C++
#define f(i,j)(i!=j)*max(0l,min(r[i],r[j])-max(l[i],l[j]))

对于 $T$ 的输入,可以把 while 替换为 for,然后在 for 的括号里输入:

C++
for(cin>>T;T--;){...}

因此,$D$ 的初始化也可以写在后面的 for 循环中,完整代码如下:

449B
#include<bits/stdc++.h>
using namespace std;
int T,n,l[1<<21],r[1<<21],x,y,z,i;long D;
#define f(i,j)(i!=j)*max(0,min(r[i],r[j])-max(l[i],l[j]))
int main(){
    for(cin>>T;T--;){cin>>n;
        for(x=y=z=i=0;i<n;++i)scanf("%d%d",&l[i],&r[i]),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;
        for(D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)}),i=0;i<n;++i)D+=min({f(i,x),f(i,y),f(i,z)});
        cout<<D<<'\n';
    }
	return 0;
}

上面为了演示保留了缩进,现在把缩进和换行都删了。注意 #include#define 分别要独占一行,其余代码占一行。

407B
#include<bits/stdc++.h>
#define f(i,j)(i!=j)*max(0,min(r[i],r[j])-max(l[i],l[j]))
using namespace std;int T,n,l[1<<21],r[1<<21],x,y,z,i;long D;int main(){for(cin>>T;T--;){cin>>n;for(x=y=z=i=0;i<n;++i)scanf("%d%d",&l[i],&r[i]),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;for(D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)}),i=0;i<n;++i)D+=min({f(i,x),f(i,y),f(i,z)});cout<<D<<'\n';}return 0;}

特性

main 函数默认返回值是 0,所以 return 0; 没有用,删了。

注意到在输入 $l,r$ 的那个 for 循环结束后,$i$ 的值一定是 $n$,而对于下一个 for 循环,$i$ 的枚举顺序并不重要,所以可以从大到小枚举。不过这样枚举会枚举到 $n$,但该完交到 OJ 上发现能 AC(每个测试点内的 $n$ 都相等),所以可以这么写。数据太弱。D+=... 写在哪里都行,总字符数量不变。

C++
for(D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)});i--;D+=min({f(i,x),f(i,y),f(i,z)}));

然后最后的 cout<<D<<'\n'; 可以写到最外面的 for 的括号里,也就是每次循环结束执行一次。可以省下一个 ;

C++
for(cin>>T;T--;cout<<D<<'\n'){...}

scanf 里的 &l[i]&r[i] 两个引用可以改成 l+ir+i

C++
scanf("%d%d",l+i,r+i)

C++ 有些神秘语法,部分环境下可以把 #include 换成 #import,省下一个字符。交到 OJ 上发现可以编译通过。

完整代码如下:

385B
#import<bits/stdc++.h>
#define f(i,j)(i!=j)*max(0,min(r[i],r[j])-max(l[i],l[j]))
using namespace std;int T,n,l[1<<21],r[1<<21],x,y,z,i;long D;int main(){for(cin>>T;T--;cout<<D<<'\n'){cin>>n;for(x=y=z=i=0;i<n;++i)scanf("%d%d",l+i,r+i),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;for(D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)});i--;D+=min({f(i,x),f(i,y),f(i,z)}));}}

还能凹

最后来处理一下 $D$ 的定义。发现如果所有变量定义在一起,都用 long 类型,则 $f$ 函数中的 max 内,需要把 0 改成 0lscanf 里需要改成 %ld。总共算下来减少了一个字符。

然后注意到 $D$ 和 $n$ 的使用范围没有任何重叠,所以把所有的 $n$ 替换成 $D$ 即可,就不用定义 $n$,减少两个字符。

最终代码

382B
#import<bits/stdc++.h>
#define f(i,j)(i!=j)*max(0l,min(r[i],r[j])-max(l[i],l[j]))
using namespace std;long T,x,y,z,i,l[1<<21],r[1<<21],D;int main(){for(cin>>T;T--;cout<<D<<'\n'){cin>>D;for(x=y=z=i=0;i<D;++i)scanf("%ld%ld",l+i,r+i),l[i]>l[x]?x=i:0,r[i]<r[y]?y=i:0,r[i]-l[i]<r[z]-l[z]?z=i:0;for(D=f(x,y)+f(x,z)+f(y,z)-max({f(x,y),f(x,z),f(y,z)});i--;D+=min({f(i,x),f(i,y),f(i,z)}));}}

提交到 OJ 上因为一些神秘原因,实际是 386B,遥遥领先。不知道还能不能凹了。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇