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的线段在边界上,当且仅当这条线段两侧的格子颜色不同。
注:输入中给出的是格子的坐标(不是点的坐标)