BG
周六的时候不太敢打,现在来看前几题还是很温暖的。。
A
n个数字,找到两个位置i和j使得a[i]!=a[j]且i-j最大
sb题,随便做。我写了动态开点线段树来维护前缀后缀min
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int INF=0x3f3f3f3f;
const int N=300005;
std:: map <int,int> last;
int min[N<<2];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void modify(int now,int tl,int tr,int x,int v) {
min[now]=std:: min(min[now],v);
if (tl==tr) return ;
int mid=(tl+tr)>>1;
if (x<=mid) modify(now<<1,tl,mid,x,v);
else modify(now<<1|1,mid+1,tr,x,v);
}
int query(int now,int tl,int tr,int l,int r) {
if (r<l) return INF;
if (tl>=l&&tr<=r) return min[now];
int mid=(tl+tr)>>1,qx=INF,qy=INF;
if (l<=mid) qx=query(now<<1,tl,mid,l,r);
if (mid+1<=r) qy=query(now<<1|1,mid+1,tr,l,r);
return std:: min(qx,qy);
}
void build(int now,int tl,int tr) {
min[now]=INF;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
build(now<<1,tl,mid),build(now<<1|1,mid+1,tr);
}
int main(void) {
// freopen("data.in","r",stdin);
int n=read(),ans=0;
build(1,1,n);
rep(i,1,n) {
int x=read();
int ra=query(1,1,n,1,x-1),rb=query(1,1,n,x+1,n);
int res=std:: min(ra,rb);
ans=std:: max(ans,i-res);
modify(1,1,n,x,i);
}
printf("%d\n", ans);
return 0;
}
B
n个数字,要求把前k个分成若干组,每组最多1个至少2个,每组的权值为这组元素的最大值
最大化k使得每组权值之和不大于给定的h
sb题,我们二分答案,排序然后dp。f[i]表示前i个权值之和最小值
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int N=500005;
LL f[N],a[N],b[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
bool check(LL h,int mid) {
rep(i,1,mid) b[i]=a[i];
std:: sort(b+1,b+mid+1);
f[1]=b[1]; rep(i,2,mid) f[i]=std:: min(f[i-1],f[i-2])+b[i];
return f[mid]<=h;
}
int main(void) {
int n=read(); LL h=read();
rep(i,1,n) a[i]=read();
int l=1,r=n,ans=1;
while (l<=r) {
int mid=(l+r)>>1;
if (check(h,mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n", ans);
return 0;
}
C
给两个n*m的01矩阵A和B,每次可以选择A的一个长和宽至少为2的子矩阵,然后翻转子矩阵的四个角落
问能否通过若干轮操作把A变成B
注意到长和宽至少为2,那么每次操作都不会改变一行或一列的异或和
那么如果某一行或某一列的异或和不等就肯定不行了。正确性的话可以感受一下?
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=2005;
int a[N][N],b[N][N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
int n=read(),m=read();
rep(i,1,n) rep(j,1,m) a[i][j]=read();
rep(i,1,n) rep(j,1,m) b[i][j]=read();
rep(i,1,n) {
int s=0;
rep(j,1,m) s+=(a[i][j]!=b[i][j]);
if (s&1) return 0&puts("No");
}
rep(j,1,m) {
int s=0;
rep(i,1,n) s+=(a[i][j]!=b[i][j]);
if (s&1) return 0&puts("No");
}
puts("Yes");
return 0;
}
D
有一个n行1e18列的矩阵A,给出第0列的元素,定义A[i,j]=A[i,0]+j
k次询问l,r求矩阵第l列到第r列中不同元素的数量
注意到问题等价于,我们给出n个数轴上的点,k次询问求所有点作为左端点,长度为给出值的区间的并的长度
那么就十分可做了。我们先给s排序,然后求出每个点与下一个点的距离d。那么对于区间相互独立的部分贡献就是数量*(r-l+1),区间交在一起的部分贡献恰好就是d了。这个按照d排序然后二分就行
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef unsigned long long LL;
const LL INF=5e18;
const int N=500005;
std:: map <LL,bool> map;
LL a[N],d[N],s[N];
LL read() {
LL x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
// freopen("data.in","r",stdin);
int w=read(),n=0;
rep(i,1,w) {
LL x=read();
if (!map[x]) {
map[x]=1;
a[++n]=x;
}
}
std:: sort(a+1,a+n+1);
rep(i,1,n) d[i]=a[i+1]-a[i]; d[n]=INF;
std:: sort(d+1,d+n+1);
rep(i,1,n) s[i]=s[i-1]+d[i];
for (int m=read();m--;) {
LL x=-read(); x+=read();
int l=1,r=n,pos=0;
while (l<=r) {
int mid=(l+r)>>1;
if (d[mid]<=x) l=mid+1,pos=mid;
else r=mid-1;
}
LL ans=s[pos]+(x+1)*(n-pos);
std:: cout << ans << " ";
}
return 0;
}
E
给n个棒,第i根长度为2i-1,有a[i]根。问最多能组成多少三角形
代码最短题。。。
可以发现组成三角形只能是(a,a,a)或者(a,a,b)这样。一个贪心策略就是我们优先匹配(a,a,b)的,然后剩下的拿去配(a,a,a),多余的留着往后用。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
int n=read();
LL a=0,ans=0;
rep(i,1,n) {
LL x=read();
LL t=std:: min(a,x/2);
ans+=t,a-=t,x-=2*t;
ans+=(x/3),x%=3,a+=x;
}
printf("%lld\n", ans);
return 0;
}