第五届图灵杯中级组题解

网址

赛时得分 \(25+50+5+1=81\),rk 67,逊死了。

赛后发现 T1 爆搜 + 剪枝有 \(50\) 分,我【】【】。

总结:还是菜。

A. 等差数列

首先特判 \(n\le 4\) 的情况。此时答案必然为 Yes,只需要两两分组即可。

由于第一个数必然在其中一个等差数列内,不妨强制令其在第一个等差数列内。

考虑 DFS。维护以下信息:当前是第几个数,第一个等差数列的公差、末尾(还没加入当前数)和第二个等差数列的公差、末尾。函数为 bool 类型,表示能否分成两个等差数列。

考虑如下搜索策略:首先在第二个等差数列没有数的情况下,能选第一段就选,实际上相当于选了一个前缀。前缀选完之后再正常选两段,分成第一个、第二个、第三个即以后三种情况讨论。搜索时还可以加几个小剪枝。

讨论过程稍微有些复杂,具体见代码:

#include<bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#define gt getchar
#define pt putchar
//typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 lll;
//typedef __uint128_t ulll;
const int N=5e5+5;
using namespace std;
inline bool __(char ch){return ch>=48&&ch<=57;}
inline int read(){
    int x=0;bool sgn=0;char ch=gt();
    while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gt();
    while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gt();
    return sgn?-x:x;
}
template<class T> inline void print(T x){
    static char st[70];short top=0;
    if(x<0)pt('-');
    do{st[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top)pt(st[top--]);
}
template<class T> inline void printsp(T x){
    print(x);
    putchar(' ');
}
template<class T> inline void println(T x){
    print(x);
    putchar('\n');
}
inline void put_str(string s){
    int siz=s.size();
    for(int i=0;i<siz;++i) pt(s[i]);
    printf("\n");
}
int T,n,a[N];
bool dfs(int now,int x_1,int x_2,int d_1,int d_2){
    // 当前搜索到第 now 个
    // 第一个等差数列当前的最后一项为 x_1,公差为 d_1
    // 第二个等差数列当前的最后一项为 x_2,公差为 d_2
    if(now>n) return 1;
    if(x_1==-1){
        // 第一个等差数列的第一个(就是 a[1]) 
        return dfs(now+1,a[now],x_2,d_1,d_2);
    }
    if(x_2==-1&&x_1!=-1&&d_1!=-1&&a[now]-x_1==d_1){
        // 第一个等差数列第三个及其后面的数,且第二个等差数列没有数,先全接上(前缀) 
        return dfs(now+1,a[now],x_2,d_1,d_2); 
    }
    bool ok=0;
    if(x_2==-1){
        // 第二个等差数列的第一个
        ok|=dfs(now+1,x_1,a[now],d_1,d_2); 
    }
    if(ok) return 1; 
    if(d_1==-1){
        // 第一个等差数列的第二个
        ok|=dfs(now+1,a[now],x_2,a[now]-x_1,d_2); 
    }
    if(ok) return 1;
    if(x_2!=-1&&d_2==-1){
        // 第二个等差数列的第二个
        ok|=dfs(now+1,x_1,a[now],d_1,a[now]-x_2); 
    }
    if(ok) return 1;
    if(x_1!=-1&&d_1!=-1&&a[now]-x_1==d_1){
        // 第一个等差数列的第三个及后面的数 
        ok|=dfs(now+1,a[now],x_2,d_1,d_2); 
    }
    if(ok) return 1;
    if(x_2!=-1&&d_2!=-1&&a[now]-x_2==d_2){
        // 第二个等差数列的第三个及后面的数 
        ok|=dfs(now+1,x_1,a[now],d_1,d_2); 
    }
    return ok;
}
signed main(){
    T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;++i) a[i]=read();
        if(n<=4) printf("Yes\n");
        else printf(dfs(1,-1,-1,-1,-1)?"Yes\n":"No\n");
    }
    return 0;
}

B. 鱼棋

考虑 BFS。

对每种棋子维护两个偏移量数组。变身、王、马的转移比较显然。对于车和象,可以枚举走的长度,那么坐标的变化量就是 \(\text{长度}\times\text{偏移量}\),遇到障碍就 break 即可。

小优化:如果搜索中途已经到达终点,那么直接输出答案走人即可。但是这个时候队列可能没有清空(如果定义在全局),那么下次 BFS 的时候不要忘记清空。

最后的问题就是坐标有点大,用 map 维护即可。

这实际上就是我的赛时做法,我写了 \(158\) 行。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#define gt getchar
#define pt putchar
//typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 lll;
//typedef __uint128_t ulll;
const int dx_w[]={-1,-1,-1,0,1,1,1,0};
const int dy_w[]={-1,0,1,1,1,0,-1,-1};
const int dx_m[]={-1,-2,-2,-1,1,2,2,1};
const int dy_m[]={-2,-1,1,2,2,1,-1,-2}; 
const int dx_c[]={-1,1,0,0};
const int dy_c[]={0,0,-1,1};
const int dx_x[]={-1,-1,1,1};
const int dy_x[]={-1,1,-1,1};
using namespace std;
inline bool __(char ch){return ch>=48&&ch<=57;}
inline int read(){
	int x=0;bool sgn=0;char ch=gt();
	while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gt();
	while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gt();
	return sgn?-x:x;
}
template<class T> inline void print(T x){
	static char st[70];short top=0;
	if(x<0)pt('-');
 	do{st[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top)pt(st[top--]);
}
template<class T> inline void printsp(T x){
	print(x);
	putchar(' ');
}
template<class T> inline void println(T x){
	print(x);
	putchar('\n');
}
inline void put_str(string s){
	int siz=s.size();
	for(int i=0;i<siz;++i) pt(s[i]);
	printf("\n");
}
int T,n,m,sx,sy,tx,ty,cnt;
char now;
map<int,map<int,char> >mp;
inline bool outmp(int x,int y){
	return x<1||x>n||y<1||y>m;
}
inline int id(char opt){
	if(opt=='K') return 1;
	else if(opt=='N') return 2;
	else if(opt=='R') return 3;
	return 4;
}
map<int,map<int,bool> >not_go;
map<int,map<int,map<int,bool> > >vis;
map<int,map<int,map<int,int> > >dis;
struct Pair{
	int x,y,id;
	Pair(int _x=0,int _y=0,int _id=0)
		:x(_x),y(_y),id(_id)
	{}
};
queue<Pair>q;
inline void bfs(){
	while(q.size()) q.pop(); 
	for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) for(int k=1;k<=4;++k) vis[i][j][k]=dis[i][j][k]=0;
	q.push(Pair(sx,sy,id(now)));
	vis[sx][sy][id(now)]=1,dis[sx][sy][id(now)]=0;
	while(q.size()){
		int x=q.front().x,y=q.front().y,opt=q.front().id;
		q.pop();
		for(int i=1;i<=4;++i){
			if(vis[tx][ty][i]==1){
				println(dis[tx][ty][i]);
				return;
			}
		}
		for(int i=1;i<=4;++i){
			if(opt!=i){
				// 切换
				if(vis[x][y][i]==1) continue;
				vis[x][y][i]=1;
				dis[x][y][i]=dis[x][y][opt]+1;
				q.push(Pair(x,y,i)); 
			}
		}
		if(opt==1){
			for(int i=0;i<8;++i){
				int xx=x+dx_w[i],yy=y+dy_w[i];
				if(outmp(xx,yy)||vis[xx][yy][opt]==1||not_go[xx][yy]==1) continue;
				q.push(Pair(xx,yy,opt));
				vis[xx][yy][opt]=1;
				dis[xx][yy][opt]=dis[x][y][opt]+1;
			}
		}else if(opt==2){
			for(int i=0;i<8;++i){
				int xx=x+dx_m[i],yy=y+dy_m[i];
				if(outmp(xx,yy)||vis[xx][yy][opt]==1||not_go[xx][yy]==1) continue;
				q.push(Pair(xx,yy,opt));
				vis[xx][yy][opt]=1;
				dis[xx][yy][opt]=dis[x][y][opt]+1;
			}
		}else if(opt==3){
			for(int i=0;i<4;++i){
				for(int len=1;;++len){
					int xx=x+len*dx_c[i],yy=y+len*dy_c[i];
					if(outmp(xx,yy)) break;
					if(vis[xx][yy][opt]==1) continue;
					if(not_go[xx][yy]==1) break;
					q.push(Pair(xx,yy,opt));
					vis[xx][yy][opt]=1;
					dis[xx][yy][opt]=dis[x][y][opt]+1;
				}
			}
		}else{
			for(int i=0;i<4;++i){
				for(int len=1;;++len){
					int xx=x+len*dx_x[i],yy=y+len*dy_x[i];
					if(outmp(xx,yy)) break;
					if(vis[xx][yy][opt]==1) continue;
					if(not_go[xx][yy]==1) break;
					q.push(Pair(xx,yy,opt));
					vis[xx][yy][opt]=1;
					dis[xx][yy][opt]=dis[x][y][opt]+1;
				}
			}
		}
	}
	for(int i=1;i<=4;++i){
		if(vis[tx][ty][i]==1){
			println(dis[tx][ty][i]);
			return;
		}
	}
	println(-1);
}
signed main(){
	T=read();
	while(T--){
		n=read(),m=read();
		cin>>now;
		sx=sy=tx=ty=cnt=0;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				cin>>mp[i][j];
				not_go[i][j]=0;
				if(mp[i][j]=='S') sx=i,sy=j;
				if(mp[i][j]=='T') tx=i,ty=j;
				if(mp[i][j]=='#') cnt++,not_go[i][j]=1; 
			}
		}
		bfs();
	}
	return 0;
}

分析一下上述算法的复杂度:变身、王和马的转移复杂度都是 \(O(1)\) 的,没有问题。但车和象转移时枚举的长度可能达到 \(O(n)\) 级别,所以复杂度是 \(O(n^3\log n)\)(map),过不了,只有 \(50\) 分。

注:这里 \(n,m\) 同级,时间复杂度分析时就只用 \(n\) 不用 \(m\) 了。

考虑剪枝:车、象如果在转移前,发现当前点已经被之前的同种类棋子从相同方向更新过了,那么直接 continue,切换到下一个方向。然后在搜索的过程中顺便记录下有没有经过即可。注意如果之前已经被访问过了也要标记,便于后面的剪枝。

对于车来说,上下、左右分别为两个方向;对于象来说,主对角线、副对角线分别为两个方向。

注意 map 还是太慢了,所以我们可以换成 unordered_map 加速。

这样可以拿到 \(65\) 分,还是过不了。

仔细思考一下,umap 的速度还是太慢了,注意到 \(n\times m\le 10^6\),所以用两维来存坐标太浪费了。我们可以将坐标降为一维,然后用普通数组存即可。

时间复杂度 \(O(n^2)\),可以通过。

最后,由于 cin 读入字符太慢了,而且 getchar 会出现各种奇怪的错误,因此我手写了一个 getchar。

此时代码长度来到了 \(185\) 行,并且我把清空操作放到了一个函数里。

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#define gt getchar
#define pt putchar
//typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 lll;
//typedef __uint128_t ulll;
const int N=1e6+5;
const int dx_w[]={-1,-1,-1,0,1,1,1,0};
const int dy_w[]={-1,0,1,1,1,0,-1,-1};
const int dx_m[]={-1,-2,-2,-1,1,2,2,1};
const int dy_m[]={-2,-1,1,2,2,1,-1,-2}; 
const int dx_c[]={-1,1,0,0};
const int dy_c[]={0,0,-1,1};
const int dx_x[]={-1,1,-1,1};
const int dy_x[]={-1,1,1,-1};
using namespace std;
inline bool __(char ch){return ch>=48&&ch<=57;}
inline int read(){
	int x=0;bool sgn=0;char ch=gt();
	while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gt();
	while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gt();
	return sgn?-x:x;
}
template<class T> inline void print(T x){
	static char st[70];short top=0;
	if(x<0)pt('-');
 	do{st[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top)pt(st[top--]);
}
template<class T> inline void printsp(T x){
	print(x);
	putchar(' ');
}
template<class T> inline void println(T x){
	print(x);
	putchar('\n');
}
inline void put_str(string s){
	int siz=s.size();
	for(int i=0;i<siz;++i) pt(s[i]);
	printf("\n");
}
int T,n,m,sx,sy,tx,ty,cnt;
char now,mp[N];
inline char getc(){
	char ch=gt();
	while(ch==' '||ch=='\n'||ch=='\r') ch=gt();
	return ch;
}
inline int get_id(int x,int y){
	return (x-1)*m+y;
}
inline bool outmp(int x,int y){
	return x<1||x>n||y<1||y>m;
}
inline int id(char opt){
	if(opt=='K') return 1;
	else if(opt=='N') return 2;
	else if(opt=='R') return 3;
	return 4;
}
bool not_go[N],vis[N][5],che[N][5],ele[N][5];
int dis[N][5];
struct Pair{
	int x,y,id;
	Pair(int _x=0,int _y=0,int _id=0)
		:x(_x),y(_y),id(_id)
	{}
};
queue<Pair>q;
inline void clear(){
	while(q.size()) q.pop(); 
	for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){
		che[get_id(i,j)][0]=che[get_id(i,j)][1]=0;
		ele[get_id(i,j)][0]=ele[get_id(i,j)][1]=0;
		for(int k=1;k<=4;++k) vis[get_id(i,j)][k]=0,dis[get_id(i,j)][k]=0;
	}
}
inline void bfs(){
	clear();
	q.push(Pair(sx,sy,id(now)));
	vis[get_id(sx,sy)][id(now)]=1,dis[get_id(sx,sy)][id(now)]=0;
	while(q.size()){
		int x=q.front().x,y=q.front().y,opt=q.front().id;
		q.pop();
		int ans=1e9;
		for(int i=1;i<=4;++i){
			if(vis[get_id(tx,ty)][i]==1){
				ans=min(ans,dis[get_id(tx,ty)][i]);
			}
		}
		if(ans!=1e9){
			println(ans);
			return;
		}
		for(int i=1;i<=4;++i){
			if(opt!=i){
				// 切换
				if(vis[get_id(x,y)][i]==1) continue;
				vis[get_id(x,y)][i]=1;
				dis[get_id(x,y)][i]=dis[get_id(x,y)][opt]+1;
				q.push(Pair(x,y,i)); 
			}
		}
		if(opt==1){
			for(int i=0;i<8;++i){
				int xx=x+dx_w[i],yy=y+dy_w[i];
				if(outmp(xx,yy)||vis[get_id(xx,yy)][opt]==1||not_go[get_id(xx,yy)]==1) continue;
				q.push(Pair(xx,yy,opt));
				vis[get_id(xx,yy)][opt]=1;
				dis[get_id(xx,yy)][opt]=dis[get_id(x,y)][opt]+1;
			}
		}else if(opt==2){
			for(int i=0;i<8;++i){
				int xx=x+dx_m[i],yy=y+dy_m[i];
				if(outmp(xx,yy)||vis[get_id(xx,yy)][opt]==1||not_go[get_id(xx,yy)]==1) continue;
				q.push(Pair(xx,yy,opt));
				vis[get_id(xx,yy)][opt]=1;
				dis[get_id(xx,yy)][opt]=dis[get_id(x,y)][opt]+1;
			}
		}else if(opt==3){
			for(int i=0;i<4;++i){
				if(che[get_id(x,y)][i/2]) continue;
				for(int len=1;;++len){
					int xx=x+len*dx_c[i],yy=y+len*dy_c[i];
					if(outmp(xx,yy)) break;
					if(vis[get_id(xx,yy)][opt]){
						che[get_id(xx,yy)][i/2]=1;
						continue;
					}
					if(not_go[get_id(xx,yy)]==1) break;
					q.push(Pair(xx,yy,opt));
					vis[get_id(xx,yy)][opt]=1;
					che[get_id(xx,yy)][i/2]=1;
					dis[get_id(xx,yy)][opt]=dis[get_id(x,y)][opt]+1;
				}
			}
		}else{
			for(int i=0;i<4;++i){
				if(ele[get_id(x,y)][i/2]) continue;
				for(int len=1;;++len){
					int xx=x+len*dx_x[i],yy=y+len*dy_x[i];
					if(outmp(xx,yy)) break;
					if(not_go[get_id(xx,yy)]==1) break;
					if(vis[get_id(xx,yy)][opt]){
						ele[get_id(xx,yy)][i/2]=1;
						continue;
					}
					q.push(Pair(xx,yy,opt));
					vis[get_id(xx,yy)][opt]=1;
					ele[get_id(xx,yy)][i/2]=1;
					dis[get_id(xx,yy)][opt]=dis[get_id(x,y)][opt]+1;
				}
			}
		}
	}
	int ans=1e9;
	for(int i=1;i<=4;++i){
		if(vis[get_id(tx,ty)][i]==1){
			ans=min(ans,dis[get_id(tx,ty)][i]);
		}
	}
	println(ans==1e9?-1:ans);
}
signed main(){
	T=read();
	while(T--){
		n=read(),m=read(),now=getc();
		gt();
		sx=sy=tx=ty=cnt=0;
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				mp[get_id(i,j)]=getc(),not_go[get_id(i,j)]=0;
				if(mp[get_id(i,j)]=='S') sx=i,sy=j;
				if(mp[get_id(i,j)]=='T') tx=i,ty=j;
				if(mp[get_id(i,j)]=='#') cnt++,not_go[get_id(i,j)]=1; 
			}
		}
		bfs();
	}
	return 0;
}

C. 差值

只会 \(5\) 分。

由于取模之后就无法比较大小了,因此考虑把每位数用数组存下来。

枚举 \(len,l_1,l_2\),如果 \(f(l_1,l_1+len-1)<f(l_2,l_2+len-1)\)swap(l1,l2),然后按照题目给定公式算出结果,并更新答案即可。比较就使用整数的比较法则即可,和十进制一样。

时间复杂度 \(O(n^4)\),枚举 \(O(n^3)\),更新答案 \(O(n)\)

这个 sb 赛时认为代码是 \(O(n^3)\) 的,赛后没发现还怒斥 tlb 评测机垃圾()

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#define gt getchar
#define pt putchar
//typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 lll;
//typedef __uint128_t ulll;
const int N=1e6+5;
const int mod=1e9+7;
const int base=998244353;
using namespace std;
inline bool __(char ch){return ch>=48&&ch<=57;}
inline int read(){
	int x=0;bool sgn=0;char ch=gt();
	while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gt();
	while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gt();
	return sgn?-x:x;
}
template<class T> inline void print(T x){
	static char st[70];short top=0;
	if(x<0)pt('-');
 	do{st[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top)pt(st[top--]);
}
template<class T> inline void printsp(T x){
	print(x);
	putchar(' ');
}
template<class T> inline void println(T x){
	print(x);
	putchar('\n');
}
inline void put_str(string s){
	int siz=s.size();
	for(int i=0;i<siz;++i) pt(s[i]);
	printf("\n");
}
int n,a[N],b[N],ans[505][505];
inline void solve(int l1,int l2,int len){
	bool cmp=1;
	for(int i=0;i<len;++i){
		if(a[l1+i]<a[l2+i]){
			cmp=0;
			break;
		}
		if(a[l1+i]>a[l2+i]) break;
	}
	if(!cmp) swap(l1,l2);
	for(int i=0;i<len;++i) b[i]=a[l1+i]-a[l2+i];
	cmp=0;
	for(int i=0;i<len;++i){
		if(b[i]<ans[len][i]){
			cmp=1;
			break;
		}
		if(b[i]>ans[len][i]) break;
	}
	if(cmp) for(int i=0;i<len;++i) ans[len][i]=b[i];
}
signed main(){
	n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	for(int len=1;len<n;++len){
		for(int i=0;i<len;++i) ans[len][i]=1e9;
		for(int i=1;i<=n-len+1;++i){
			for(int j=i+1;j<=n-len+1;++j){
				solve(i,j,len);
			}
		}
	}
	for(int i=1;i<n;++i){
		ll sum=0,ksm=1;
		for(int j=i-1;j>=0;--j){
			sum=(sum+ans[i][j]*ksm%mod)%mod;
			sum=(sum%mod+mod)%mod;
			ksm=(ksm*base)%mod;
		}
		printsp(sum);
	}
	return 0;
}

D. 基础循环结构练习题

首先考虑 \(b_i\) 递增时怎么做。

考虑一下取模操作的用途。经过思考,它可以起到消除最大值的作用。

这看似没什么用,但是它却可以帮助我们控制相邻两项的差

举个例子,我们有 \(a\) 数组 \([1,2,3]\),然后我们进行以下操作:

  • 全局对 \(3\) 取模,此时序列变为 \([1,2,0]\)

  • 全局加 \(x\),此时序列为 \([1+x,2+x,x]\)

  • 全局对 \(2+x\) 取模,此时序列为 \([1+x,0,x]\)

这样我们就将 \(a_3-a_2\) 的值控制为了 \(x\)

因此,我们只需要让 \(a_1=b_1\),然后保证对于任意 \(i\ge2\) \(a_i-a_{i-1}=b_i-b_{i-1}\) 即可。

具体地,我们记录 \(sum\) 表示全局加了多少。然后从 \(n\)\(1\) 枚举 \(i\)(当前的最大值),全局对 \(sum+i\) 取模(使 \(a_i\) 变为 \(0\)),然后全局加上 \(b_i-b_{i-1}\)(控制差值),最后让 \(sum\) 加上 \(b_i-b_{i-1}\) 即可。

这样对于每个 \(i\) 都会进行两次操作。总操作次数 \(2n\),期望得分 \(35\) 分。

代码不写了。

实际上刚才的做法很具有启发性。我们考虑让 \(b\) 变成递增的:选取一个 \(>\max b_i\) 的值 \(B\),然后 \(b_i\to b_i+iS\),很明显此时序列是递增的。用相同的方法使得 \(a\) 变为此时的 \(b\) 序列,最后再对 \(B\) 全局取一次模即可。

总操作次数 \(2n+1\),期望得分 \(100\) 分。

这个算法的时间复杂度是 \(O(n)\) 的,所以 \(n\) 完全可以开到 \(10^7\)可能这个数据范围单纯只是不想让答案爆掉 int

最后注意一下,\(B\) 应该比 \(b\) 的范围(\(10^5\))大,而不是 \(a\) 的范围(\(n\)\(10^3\))!

代码:

#include<bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#define gt getchar
#define pt putchar
//typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 lll;
//typedef __uint128_t ulll;
const int N=1005;
const int B=1e5+5;
using namespace std;
inline bool __(char ch){return ch>=48&&ch<=57;}
inline int read(){
	int x=0;bool sgn=0;char ch=gt();
	while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gt();
	while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gt();
	return sgn?-x:x;
}
template<class T> inline void print(T x){
	static char st[70];short top=0;
	if(x<0)pt('-');
 	do{st[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
    while(top) pt(st[top--]);
}
template<class T> inline void printsp(T x){
	print(x);
	putchar(' ');
}
template<class T> inline void println(T x){
	print(x);
	putchar('\n');
}
inline void put_str(string s){
	int siz=s.size();
	for(int i=0;i<siz;++i) pt(s[i]);
	printf("\n");
}
int n,a[N],b[N];
signed main(){
	n=read();
	for(int i=1;i<=n;++i) a[i]=i,b[i]=read()+i*B;
	println(2*n+1);
	int sum=0;
	for(int i=n;i;--i){
		printf("2 %d\n",sum+i);
		printf("1 %d\n",b[i]-b[i-1]);
		sum+=(b[i]-b[i-1]);
	} 
	printf("2 %d\n",B);
	return 0;
}
posted @ 2024-02-28 15:20  Southern_Dynasty  阅读(33)  评论(1编辑  收藏  举报