目录
A 、All-one Matrices (单调栈)
题意:
给出01矩阵,计算有多少个全1矩阵,并且每个全一矩阵必须是所能达到的最大的。
分析:
这类问题,一般解决就是两个方向:
A:压缩一维,即枚举上下边界,然后复杂度O(N^3);
B:广告牌问题,即枚举下边界s,那么就可以看成s为底的一些高楼,再高楼上布置广告牌,复杂度O(N^2)。
A类问题 2019牛客第三场F
B类问题 HDU1506,2019牛客多校第二场H
这个题也是一个B类问题。
注意的有两点,1.这个区间只算一次(去重),2.这个区间底下全是1则不算。
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pid pair<double,double>
#define pil pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rush() int T;scanf("%d",&T);while(T--)
#define sc(a) scanf("%d",&a)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//#define gc getchar
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read(){
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
const int maxn=3e3+10;
int L[maxn],R[maxn];
int n,m;
char s[maxn][maxn];
int h[maxn][maxn];
int vis[maxn][maxn];
int num[maxn];
int ans;
void solve(int t){
rep(i,1,m) L[i]=R[i]=i;
rep(i,2,m){
int now=i;
while(now>1&&h[t][i]<=h[t][now-1]) now=L[now-1];
L[i]=now;
}
for(int i=m-1;i>=1;i--){
int now=i;
while(now<m&&h[t][i]<=h[t][now+1]) now=R[now+1];
R[i]=now;
}
rep(i,1,m) num[i]=num[i-1]+(s[t+1][i]=='1');
rep(i,1,m){
if(h[t][i]==0) continue;
if(vis[L[i]][R[i]]==t) continue;
if(num[R[i]]-num[L[i]-1]==R[i]-L[i]+1) continue;
ans++;
vis[L[i]][R[i]]=t;
}
}
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d%d",&n,&m);
rep(i,1,n){
rep(j,1,m){
scanf(" %c",&s[i][j]);
if(s[i][j]=='1') h[i][j]=h[i-1][j]+1;
}
}
rep(i,1,n) solve(i);
printf("%d\n",ans);
return 0;
}
B 、Beauty Values (计算贡献)
题意:
计算所有区间不同数字的个数;
分析:
因为是计算所有区间所有可以直接算贡献,如果问的是任意一个区间,则可用主席树。
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
int a[maxn];
int pre[maxn];
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=1ll*i*(n-i+1);
ans-=1ll*pre[a[i]]*(n-i+1);
pre[a[i]]=i;
}
printf("%lld\n",ans);
return 0;
}
C 、CDMA (递归)
题意:
给出一个m,计算m*m的矩阵使得每一行相乘结果都为零。
分析:
考虑由小矩阵构造大矩阵,所以我们可以这样构造,将小矩阵放在大矩阵的左上,右上,左下,右下均取反,那么构造出来的一个矩阵就是所求。
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1030;
int s[maxn][maxn];
void dfs(int x1,int y1,int x2,int y2,int dir,int dep){
if(dep==1){
s[x1][y1]=1*dir;
s[x1][y1+1]=1*dir;
s[x1+1][y1]=1*dir;
s[x1+1][y1+1]=-1*dir;
return;
}
int mid=1<<(dep-1);
dfs(x1,y1,x1+mid-1,y1+mid-1,dir,dep-1);
dfs(x1,y1+mid,x1+mid-1,y2,dir,dep-1);
dfs(x1+mid,y1,x2,y1+mid-1,dir,dep-1);
dfs(x1+mid,y1+mid,x2,y2,dir*-1,dep-1);
}
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int m;
scanf("%d",&m);
int i=0;
for(;1<<i<m;i++);
dfs(1,1,m,m,1,i);
for(i=1;i<=m;i++){
for(int j=1;j<=m;j++){
printf("%d ",s[i][j]);
}
printf("\n");
}
return 0;
}
D、 Distance (三维树状数组)
题意:
两种操作:
1 x,y,h表示在x,y,h位置添加一个点
2 x,y,h表示询问与这个位置最近的点的曼哈顿距离是多少
分析:
将绝对值进行拆分,可以得到8种情况,所以将8种情况分别建立树状数组计算
我们就去八个树状数组中查询小于等于当前值的最大值,做差取最小值即可。
这么做为什么对呢,因为将拆分后的情况总能转化成这种形式。
哈希是为了保证所有的坐标都有不同的数字表示,
参考博客:https://blog.csdn.net/qq_41955236/article/details/99685766
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pid pair<double,double>
#define pil pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rush() int T;scanf("%d",&T);while(T--)
#define sc(a) scanf("%d",&a)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//#define gc getchar
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read(){
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
const int maxn=5e6+10;
int dx[]={1,1,1,1,-1,-1,-1,-1};
int dy[]={1,1,-1,-1,1,1,-1,-1};
int dz[]={1,-1,1,-1,1,-1,1,-1};
void deal(int i,int x,int y,int z,int &nx,int &ny,int &nz){
nx=x*dx[i];
ny=y*dy[i];
nz=z*dz[i];
}
struct BIT{
int mx[maxn],n,m,h;
int g_hash(int x,int y,int z){
return x*(2*m+2)*(2*h+2)+y*(2*h+2)+z;
}
void init(int nn,int mm,int hh){
n=nn,m=mm,h=hh;
for(int i=0;i<maxn;i++) mx[i]=-inf;
}
int lowbit(int x){
return x&(-x);
}
void update(int x,int y,int z,int v){
for(int i=x;i<2*n+5;i+=lowbit(i)){
for(int j=y;j<2*m+5;j+=lowbit(j)){
for(int k=z;k<2*h+5;k+=lowbit(k)){
mx[g_hash(i,j,k)]=max(mx[g_hash(i,j,k)],v);
}
}
}
}
int query(int x,int y,int z){
int ret=-inf;
for(int i=x;i;i-=lowbit(i)){
for(int j=y;j;j-=lowbit(j)){
for(int k=z;k;k-=lowbit(k)){
ret=max(ret,mx[g_hash(i,j,k)]);
}
}
}
return ret;
}
}B[8];
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int n,m,h,q;
scanf("%d%d%d%d",&n,&m,&h,&q);
for(int i=0;i<8;i++) B[i].init(n,m,h);
while(q--){
int op,x,y,z;
scanf("%d%d%d%d",&op,&x,&y,&z);
if(op==1){
for(int i=0;i<8;i++){
int nx,ny,nz;
deal(i,x,y,z,nx,ny,nz);
B[i].update(n+nx+1,m+ny+1,h+nz+1,nx+ny+nz);
}
}else{
int ans=inf;
for(int i=0;i<8;i++){
int nx,ny,nz;
deal(i,x,y,z,nx,ny,nz);
ans=min(ans,nx+ny+nz-B[i].query(n+nx+1,m+ny+1,h+nz+1));
}
printf("%d\n",ans);
}
}
return 0;
}
E 、Explorer (线段树+并查集按秩合并)
题意:
给定一个无向图,有n个点m条边,每条边有四个属性u,v,l,r,表示连接u,v的这条边允许通过的路人的体形范围在[l,r],问从1走到n的可行体形有几个
分析:
首先把区间离散化,然后建立一棵以区间为关键字的线段树,再把所有边都按区间加进对应的线段树节点。然后从线段树的根节点不断向下dfs,每次用按秩(即深度)合并优化并查集,不能用路径压缩,因为回溯的时候要撤销并查集操作。到了叶子结点的时候查询下1和n是否在一个集合里,是的话就加上这个区间的贡献,不是的话就继续向下dfs。
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pid pair<double,double>
#define pil pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rush() int T;scanf("%d",&T);while(T--)
#define sc(a) scanf("%d",&a)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//#define gc getchar
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read(){
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
const int maxn=2e5+10;
struct node{
int u,v,l,r;
node(){}
node(int u,int v,int l,int r):u(u),v(v),l(l),r(r){}
}p[maxn];
int a[maxn<<1];
vector<pii> tree[maxn<<2];
pii V;
int n,m;
void build(int i,int l,int r,int x,int y){
if(l==x&&y==r){
tree[i].push_back(V);
return;
}
int mid=l+r>>1;
if(y<=mid) build(i<<1,l,mid,x,y);
else if(x>mid) build(i<<1|1,mid+1,r,x,y);
else build(i<<1,l,mid,x,mid),build(i<<1|1,mid+1,r,mid+1,y);
}
int fa[maxn<<1];
vector<int> t[100];
int rk[maxn<<1];
int ans;
int find(int x){
return fa[x]==x?x:find(fa[x]);
}
void join(int x,int y,int dep){
x=find(x),y=find(y);
if(x==y) return;
if(rk[x]<=rk[y]){
fa[x]=y;
t[dep].push_back(x);
if(rk[x]==rk[y]) rk[y]++;
}else{
fa[y]=x;
t[dep].pb(y);
}
}
void dfs(int i,int l,int r,int dep){
t[dep].clear();
for(auto &tmp:tree[i]) join(tmp.fi,tmp.se,dep);
// cout<<l<<" "<<r<<endl;
if(l==r){
if(find(1)==find(n)) ans+=a[r+1]-a[l];
for(auto& tmp:t[dep]) fa[tmp]=tmp;
return ;
}
int mid=l+r>>1;
dfs(i<<1,l,mid,dep+1);
dfs(i<<1|1,mid+1,r,dep+1);
for(auto& tmp:t[dep]) fa[tmp]=tmp;
}
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
for(int i=0;i<maxn*2;i++) fa[i]=i;
scanf("%d%d",&n,&m);
int cnt=0;
rep(i,1,m){
int u,v,l,r;
scanf("%d%d%d%d",&u,&v,&l,&r);
p[i]=node(u,v,l,r);
a[++cnt]=l,a[++cnt]=r+1;
}
sort(a+1,a+1+cnt);
cnt=unique(a+1,a+1+cnt)-a-1;
a[cnt+1]=cnt+1;
rep(i,1,m){
V=mp(p[i].u,p[i].v);
int l=lower_bound(a+1,a+1+cnt,p[i].l)-a;
int r=lower_bound(a+1,a+1+cnt,p[i].r+1)-a;
build(1,1,cnt,l,r-1);
}
ans=0;
dfs(1,1,cnt,1);
printf("%d\n",ans);
return 0;
}
G、Gemstones (模拟)
题意:
给出一个字符串每次消三个长度相同的,问消几次。
分析:
直接用栈模拟即可。
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
string s;
cin>>s;
vector<char> sta;
if(s.size()<=2){
cout<<"0"<<endl;
return 0;
}
sta.push_back(s[0]);
sta.push_back(s[1]);
sta.push_back(s[2]);
int ans=0;
for(int i=3;i<s.size();i++){
while(sta.size()>=3){
bool flag=true;
int len=sta.size();
if(sta[len-1]==sta[len-2]&&sta[len-1]==sta[len-3]){
ans++;
sta.pop_back();
sta.pop_back();
sta.pop_back();
flag=false;
}
if(flag) break;
}
sta.push_back(s[i]);
}
while(sta.size()>=3){
bool flag=true;
int len=sta.size();
if(sta[len-1]==sta[len-2]&&sta[len-1]==sta[len-3]){
ans++;
sta.pop_back();
sta.pop_back();
sta.pop_back();
flag=false;
}
if(flag) break;
}
cout<<ans<<endl;
return 0;
}
J 、Just Jump (DP+组合计数)
题意:
起点为0需要走到终点L,每次至少走d步,有m次攻击,ti时刻会出现在pi位置,也就是说在ti时刻不能在pi位置
分析:
参考的这篇博客:https://blog.csdn.net/ftx456789/article/details/99306117
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pid pair<double,double>
#define pil pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rush() int T;scanf("%d",&T);while(T--)
#define sc(a) scanf("%d",&a)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define PI acos(-1.0)
#define E exp(1.0)
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//#define gc getchar
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read(){
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
const int maxn=1e7+10;
const ll mod=998244353;
struct node{
ll t,p;
bool operator < (const node& a) const{
return t<a.t;
}
}a[3005];
ll sum[maxn],dp[maxn],f[maxn];
ll fac[maxn];
ll quick_pow(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll inv(ll a){
return quick_pow(a,mod-2,mod);
}
ll C(ll n,ll m){
if(m>n) return 0;
if(n<0||m<0) return 0;
return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
ll L,d,m;
scanf("%lld%lld%lld",&L,&d,&m);
f[0]=sum[0]=1;
fac[0]=1ll;
rep(i,1,maxn-1) fac[i]=fac[i-1]*(ll)i%mod;
rep(i,1,L){
if(i<d) f[0]=0;
else {
f[i]=sum[i-d];
}
sum[i]=(sum[i-1]+f[i])%mod;
}
rep(i,1,m) scanf("%lld%lld",&a[i].t,&a[i].p);
sort(a+1,a+1+m);
rep(i,1,m){
dp[i]=C(a[i].p-d*a[i].t+a[i].t-1,a[i].t-1)%mod;
rep(j,1,i-1) dp[i]=(dp[i]-dp[j]*C(a[i].p-a[j].p-d*(a[i].t-a[j].t)+a[i].t-a[j].t-1,a[i].t-a[j].t-1)%mod+mod)%mod;
}
ll ans=f[L];
rep(i,1,m){
ans=(ans-dp[i]*f[L-a[i].p]%mod+mod)%mod;
}
printf("%lld\n",ans);
return 0;
}