2019年8月6日本地题库提高组 gcd+LIS+单调队列优化+bfs+?

A 蛋糕切割

Garfield非常喜欢巧克力蛋糕。奇怪的是,她把蛋糕分成了N行M列的网格。馋嘴的她想知道,沿对角线的一刀能切到的网格数。
对于50%的数据,N,M ≤ 10^3,
对于100%的数据,N,M ≤ 10^9。

枚举数据并分析可得,答案即n+m-gcd(m,n)

#include <cstdio>

using namespace std;

int n,m;

int gcd(int a,int b){
	 if (b==0) return a;
	 int k=gcd(b,a%b);
	 return k;
}

int main(){
	 scanf("%d%d",&n,&m);
	 if (n>=m) printf("%d",n+m-gcd(n,m));else
	     printf("%d",n+m-gcd(m,n));
}

B 膜拜神牛

Garfield听说OI班有N头神牛,每头神牛有两个属性,算法能力和思维能力,分别以Ai和Bi表示。如果神牛i和神牛j满足Ai ≥ Aj且Bi ≤ Bj,那么两位神牛会互相膜拜。Garfield认为膜拜是不和谐的,所以她想知道,最大的不存在膜拜关系的子集大小。
对于40%的数据,N ≤ 10^3,
对于100%的数据,N ≤ 10^5。

以ai为第一关键字,bi为第二关键字排序,ai升序,bi降序
对排序后的bi求最长上升子序列
O(n log n)

#include <cstdio>
#include <algorithm>

using namespace std;int n,ans;

struct node{
	 int a,b;
}c[100005];
int f[100005];

bool comp(node a,node b){
 	if (a.a==b.a) return a.b>b.b;
	 return a.a<b.a;
}

int main(){
	 scanf("%d",&n);
	 for (int i=1;i<=n;i++)
		  scanf("%d%d",&c[i].a,&c[i].b);
	 sort(c+1,c+1+n,comp);
	 for (int i=1;i<=n;i++){
		  if (c[i].b>f[ans]){
			   f[++ans]=c[i].b;
		  }else{
			   int l=1,r=ans,k=0;
			   while (l<=r){
				    int mid=(l+r)/2;
			   	 if (f[mid]>=c[i].b) r=mid-1,k=mid;else l=mid+1;
			   }
			   f[k]=c[i].b;
		  }
	 }
	 printf("%d",ans);
}

C 矩形统计

Garfield小时候数学非常好,这与她喜欢数格子是分不开的。现在她有一张边长为N的方格纸(有若干破损),她想知道这张纸能够裁出多少矩形。
对于50%的数据,N ≤ 20,
对于100%的数据,N ≤ 1000。
将破损表示为1

010
010
000
把这样的一张纸表示为矩形

		0 0
		0 0
		000

这时就把矩形从左向右加入队列,当后加的矩形比前面的矩形矮时,要弹出高的矩形高出的部分,并加入答案,然后把消掉高出部分的矩形加入后加的矩形,也就是后加的矩形宽度增加。
加入答案时,用矩形的高度*宽度(宽度:对于高度为1的一行格子,可以取多少种矩形)
emm…开long long
矩形的高度用up[i][j]表示,即格子(i,j)向上多少个格子到破损格子

#include <cstdio>
#include <cstring>

using namespace std;int n,cw;

long long ans;
int up[5003][5003],a[5003][5003];
int w[5003],u[5003],h;
int s[5003];

int main(){
	 scanf("%d",&n);
	 for (int i=1;i<=n;i++)
	  for (int k=1;k<=i;k++)
		   s[i]+=i-k+1;
	 for (int i=1;i<=n;i++){
		  char ch[5003];
		  scanf("%s",ch+1);
	  for (int j=1;j<=n;j++) 
		   a[i][j]=ch[j]-'0';
	 }
	 for (int i=1;i<=n;i++){
		  for (int j=1;j<=n;j++) 
		  if (a[i][j])
		   for (int k=i+1;a[k][j]==0&&k<=n;k++)
		    up[k][j]=k-i;
	 }
	 for (int i=1;i<=n;i++)
		  for (int j=1;j<=n;j++)
		  if (a[i][j]==0&&up[i][j]==0) up[i][j]=i;
			 for (int i=1;i<=n;i++){
				h=0;
				for (int j=1;j<=n+1;j++)
				  if (up[i][j]==0){
				  	while (h){
						ans=(long long)ans+s[w[h]]*(u[h]-u[h-1]);
   						w[h-1]+=w[h];
						h--;
 				 	}
   					w[0]=0;
				  }else{
			          if (up[i][j]>u[h]) u[++h]=up[i][j],w[h]=1;else
			 	 {
 					   cw=0;
					    while (u[h]>up[i][j]&&u[h-1]>up[i][j]){
 				        	   cw+=w[h];
						   ans=(long long)ans+s[cw]*(u[h]-u[h-1]);
 						   h--;
					    }
  					  if (u[h]>up[i][j]) 
  					  cw+=w[h] , ans=(long long)ans+s[cw]*(u[h]-up[i][j]) , h--;
					    w[++h]=cw+1;u[h]=up[i][j];
				       while (u[h-1]==up[i][j]) w[h-1]+=w[h],h--;
 				  }
			  }
		 }
	 printf("%lld",ans);
}

D 逃亡路径

由于不能与Garfield和睦相处,Odie决定逃亡。不幸的他逃到了一个矩形湖泊。湖泊的长为N,宽为M,初始时Odie位于位置(1,1)。Garfield想要知道可怜的Odie有到达位置(N,M)的最短路径条数(不能跳出湖泊边界)。另外,神奇的Odie移动方式类似国际象棋的骑士。
对于50%的数据,N ≤ 5,
对于100%的数据,N ≤ 100。
输出一个整数,表示最短路径的条数(模9901输出即可)。

bfs暴搜啦

#include <cstdio>

using namespace std;

const int dx[10]={-2,-2,-1,1,2,2,1,-1};
const int dy[10]={-1,1,2,2,1,-1,-2,-2};
int n,m,ans;
int a[106][106],f[106][106];
int v[1000000][4],h,t;

void bfs(){
	 int flag=0;
	 t=1;v[1][0]=1;v[1][1]=1;v[1][2]=1;a[1][1]=1;f[1][1]=1;
	 while ((h<t)&&(!flag||v[h+1][2]==flag)){
		  int x=v[++h][0],y=v[h][1];
		  for (int i=0;i<8;i++)
		  if (x+dx[i]>0&&x+dx[i]<=n&&y+dy[i]>0&&y+dy[i]<=m){
		   	if (a[x+dx[i]][y+dy[i]]==0)   
		   		v[++t][0]=x+dx[i],v[t][1]=y+dy[i],v[t][2]=v[h][2]+1,a[x+dx[i]][y+dy[i]]=v[h][2]+1;
			if (a[x+dx[i]][y+dy[i]]==0||v[h][2]+1==a[x+dx[i]][y+dy[i]])   
			 	f[x+dx[i]][y+dy[i]]=(f[x+dx[i]][y+dy[i]]+f[x][y])%9901;
 			if (x+dx[i]==n&&y+dy[i]==m){
			    flag=v[h][2];
   			}
		  }
	 }
}

int main(){
	 scanf("%d%d",&n,&m);
	 bfs();
	 printf("%d",f[n][m]%9901);
}

E 矩形反色

gmh77有一个无限大的方格图,由无限个1*1的格子构成,每个格子有黑白两色。初始所有格子都是白色。

现在gmh77会进行n次操作,每次把一个矩形区域反色(即黑变白,白变黑),求n次操作后得出的图形的周长(即边界长)。

边界的定义:定义一条长度为1的线段在边界上,当且仅当这条线段两侧的格子颜色不同。

注:输入中给出的是格子的坐标(不是点的坐标)

希望我们都能像对方一样勇敢。——蒋丞

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值