压行导论

压行是个好东西,本文将以luoguP5661(本代码提交0分)和其余零碎代码为例,向你讲解如何正确压行

原版未压行(格式化邪教):

#include<bits/stdc++.h>
using namespace std;
int opt,n,ans,top,m=1,k;
int t[100010],p[100010],yh[100010],sj[100010];
bool r[100010];
int main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>opt>>p[i]>>t[i];
		if(opt==0) {
			yh[++top]=p[i],sj[top]=t[i],ans+=p[i];
		} else {
			k=0;
			for(int j=m; j<=top; j++) {
				if(r[j]) continue;
				if(t[i]+sj[j]>45) m=j;
				else if(yh[j]>=p[i]) {
					k=j;
					r[k]=true;
					break;
				}
			}
			if(!k) ans+=p[i];
		}
	}
	cout<<ans;
}

0.为什么压行

  • 技术含量不高
  • 使代码更短
  • 可读性更高(划掉)
  • 方便调试(划掉)

虽然格式化邪教也有着不少优点,但是它缺少了动手完成的成就感 ,而且,压行,是神教,正道!!!!!!!!!!!!!!!!!!!!!!!

有人说

华丽的压行技巧并不能提升代码水平,只有不到位的压行技巧导致爆零。

但是,压行一定可以保证代码的可读性

I.压行基础

I.I 逗号的使用

当多条赋值语句和函数各占一行时,会让人不爽,这时,逗号出现了,他可以对其进行连接(注意,他的优先级最低,且返回最后一个值)。

原版

k=j;
r[k]=true;

压行

k=j,r[k]=true;

I.II 常数替代

原版代码的定义中我们可以发现数据范围反复出现,此时我们可以定义常量。

原版:

int t[100010],p[100010],yh[100010],sj[100010];
bool r[100010];

压行?(应该只是压代码):

//不建议用const,constexpr可以自己识别某表达式是否是常量
constexpr int N=100010;
int t[N],p[N],yh[N],sj[N];
bool r[N];

I.III 删掉大括号

答括号有时候必须得用到,但是它的出现必定会使代码的行数增加三行至以上,当我们用其他压行技巧把大括号里的内容压到只有一行时,删掉他(函数不行)!

for (int i=0;i<n;i++)
{
  for(int j=0;j<n;j++)
  {
    scanf("%d",&a[i][j]);
  }
}

压行for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",a[i][j]);

II. 中级压行

II.I 三目运算符

条件 ? 如果为真执行 : 如果为假执行 里面不能塞代码块哟

if else可以扔掉了,再注意一下优先级即可。

如max函数

int max(int a,int b)
{
  if(a>b) return a;
  else return b;
}

int max(int a,int b){return a>b?a:b;}

II.II 短路原理

请先看代码:

#include<stdio.h>
int main()
{
	int a=100,b=200;
	if(a>99&&b++) 
	{
		if(a>200&&b=b-2) ;
	}
	printf("%d %d",a,b);
	return 0;
}

输出为100 201

这就是短路性质:

如果第一个条件(左边的条件)为真(true),则不会计算第二个条件(右边的条件),整个表达式被认为为真。

只有当第一个条件为假(false)时,才会继续计算第二个条件。 如果第二个条件为真,整个表达式被认为为真;如果第二个条件也为假,整个表达式被认为为假。

而例如a=b+1返回的值是计算后的a,所以通过这种方法我们可以把:

if(a%b==0)
{
  sum++;
  break;
}

改为

if(a%b==0&&++sum) break;//不要sum++防止sum的初始为0而导致条件为假

II.III 熟练的STL

C++中的STL库真的很好用的(不要跟我一样用C++但沉迷于C语言无法自拔)

比如map可以自定义下标 就map<int,int>好像没用对吧,这个下标可以存负数的,内部利用红黑树自动排序,但是取用元素时好像是O(log n)

III 高级压行

III.I 巧用define

先是一段引用

define里可以塞一些“变量”,例如大家常用的 #define max(a, b) ((a)>(b)? (a): (b))#define lowbit(x) ((x)&-(x))

##define 里的连接符:它可以将两个常量字符串变量字符串连接。于是我们可以写一个这样的 define 句子: #define rep(i, a, b) for(int i=(a), i##up=(b); i<=i##up; ++i)

引用结束

但是,需要注意的是define只是单纯的替换

ans=max(fun1(),ans),他完全等价ans=(fun1()>ans?fun1(),ans),这意味着fun1函数将会执行两次,而不是先计算fun1()的值,在进行比较,将ans置为其中计算好的较大的值。

所以,define虽好,但也不可以滥用

III.II 巧用lambda表达式

上文中我们提到三元运算符中不能放代码块,但是lambda表达式可以。关于它的使用请自行bdfs或这边粗略看一下,没时间讲太多。

捕获变量时建议隐式引用捕获,这样你可以不用写太多。

例子:

for(scanf("%d",&n);i<=n;i++)
{
	scanf("%d%d%d",&opt,p+i,t+i);
	if(!opt) yh[++top]=p[i],sj[top]=t[i],ans+=p[i]
	else
	{
		func();
		for(k=0,f=1,j=m;j<=top&&f;j++) r[j]?1:(t[i]-sj[j]>45?m=j:(yh[j]>=p[i]&&(k=j)&&(r[k]=true)?f=0:1));
		if(!k) ans+=p[i];
	}
}

运用lambda技巧后

auto func=[&](){for(k=0,f=1,j=m;j<=top&&f;j++) r[j]?1:(t[i]-sj[j]>45?m=j:(yh[j]>=p[i]&&(k=j)&&(r[k]=true)?f=0:1));};
for(scanf("%d",&n);i<=n;i++) scanf("%d%d%d",&opt,p+i,t+i),(!opt)?yh[++top]=p[i],sj[top]=t[i],ans+=p[i]:(func(),!k?ans+=p[i]:6);

IV. 其他技巧

(零零散散的,以后再整理吧)

IV.I 压输入输出

输入时可以压行到变量的定义中(我有时候压到for循环中)的,使用逗号运算符即可(cin cout输入本质上是一个类的重载运算符)

例:

int x,y=(cin>>x,0);

由于scanf,printf函数的参数读入是依赖第一个字符串的。所以scanf("%d",&x,y=100);是可以的 此方法有时会造成爆0,取消使用

IV.II 使用工具

必备工具:压行机

注:有时候可能太卡进不去,所以建议Ctrl + S先行保存

当真的压无可压的时候可使用(所以,这往往才是压行的最后一步)

IV.III 剩余的其他

  • 主函数中int可省略,这是默认的。
  • return 0;也可以省略。
  • printf返回的是输出长度(显然不会为0)所以是return!printf("%d",ans);

结语

最后,勤加练习,你的压行便会大成:

//本代码提交0分
#include<stdio.h>
const int N=100010;
int opt,n,ans,top,m=1,k,f;
int t[N],p[N],yh[N],sj[N];
bool r[N];
int main() {
	int i=1,j;
	for(auto func=(scanf("%d",&n),[&](){for(k=0,f=1,j=m;j<=top&&f;j++) r[j]?1:(t[i]-sj[j]>45?m=j:(yh[j]>=p[i]&&(k=j)&&(r[k]=true)?f=0:1));});i<=n;i++) scanf("%d%d%d",&opt,p+i,t+i,(!opt)?yh[++top]=p[i],sj[top]=t[i],ans+=p[i]:(func(),!k?ans+=p[i]:6));
	return!printf("%d",ans);
}//为了代码的可读性,还未使用压行机

(如需转载,请标明出处)

本人实力不济,如有错误或其他建议及补充(包括但不限于压行技巧),欢迎指出。

零零散散的未整理的其他技巧或需注意的点

参考资料

压行万岁

posted @ 2024-10-03 10:08  AC-13-13  阅读(29)  评论(0编辑  收藏  举报