a
题面:
有一个 \(n\times m\) 的 \(01\) 矩阵,求其中 \(1\) 的个数在 \([l,r]\) 的子矩阵数量
题解:
令 \(f_k\) 为 \(1\) 的个数 \(\le k\) 的子矩阵数量,答案为 \(f_r-f_{l-1}\) 。
\(n\) 较小,暴力枚举上下区间,在内用双指针维护和小于等于 \(k\) 的段,复杂度 \(\text{O}(n^2m)\) 。
代码:
#include<cstdio>
#include<bitset>
#define int long long
constexpr int N=35,M=50005;
int n,m,L,R,sum[M],ss[N][M];
char s[M];
std::bitset<M>a[N];
int solve(int x){
if(x<0)return 0;
int res=0;
for(int i=1;i<=n;i++)for(int j=i;j<=n;j++){
for(int k=1;k<=m;k++)sum[k]=sum[k-1]+ss[j][k]-ss[i-1][k];
for(int l=1,r=0;l<=m;l++){
for(;r<m&&sum[r+1]-sum[l-1]<=x;r++);
res+=r-l+1;
}
}
return res;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)a[i][j]=s[j]=='1';
}
for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)ss[i][j]=ss[i-1][j]+(int)a[i][j];
scanf("%lld%lld",&L,&R),printf("%lld\n",solve(R)-solve(L-1));
return fflush(stdout),fclose(stdin),fclose(stdout),0;
}
b
题面:
有一个 \(n\times m\) 的矩阵 \(a_{n,m}\) 每一行不选或者选一个数,至少选一个数,求所有选数方案的选出数的 \(\gcd\) 的总和。
题解:
令 \(cnt_{i,j}\) 表示第 \(i\) 行 \(j\) 的倍数的出现次数,筛出质数后用类似高维前缀和的方法求。
令 \(f_i\) 表示 \(\gcd\) 为 \(i\) 的总情况数。
直接计算即可,复杂度 \(\text{O}(nA\log\log A+A\log A)\)
代码:
#include<cstdio>
#define Max(x,y) ((x)<(y)&&((x)=(y)))
#define Add(x,y) (((x)+=(y))>=mod&&((x)-=mod))
#define mul(x,y) ((x)*(y)%mod)
#define add(x,y) ((x)+(y)>=mod?(x)+(y)-mod:(x)+(y))
#define sub(x,y) (add((x),mod-(y)))
#define Mul(x,y) ((x)=mul((x),(y)))
template<typename T>inline void read(T&x){
x=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
typedef long long ll;
const int N=25,M=100005,A=1000005,INF=0x3f3f3f3f;
const ll mod=1000000007;
int a[N][M],n,m,maxa,minp[A],p[A],cntp;
ll cnt[N][A],f[N],ans;
bool isp[A];
int main(){
read(n),read(m);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)read(a[i][j]),cnt[i][a[i][j]]++,Max(maxa,a[i][j]);
for(int i=2;i<=maxa;i++)isp[i]=1;
for(int i=2;i<=maxa;i++)if(isp[i]){
p[++cntp]=i;
for(int j=i<<1;j<=maxa;j+=i)isp[j]=0;
}
for(int i=1;i<=n;i++)for(int j=1;j<=cntp;j++)for(int k=maxa/p[j];k;k--)cnt[i][k]+=cnt[i][p[j]*k];
for(int i=maxa;i;i--){
int pro=1,sum=1;
for(int j=1;j<=n;j++)Mul(pro,add(cnt[j][i],1));
for(int j=i<<1;j<=maxa;j+=i)Add(sum,f[j]);
f[i]=sub(pro,sum);
}
int tmp=1;
for(int i=1;i<=20;i++)Mul(tmp,7);
for(int i=1;i<=maxa;i++)Add(ans,mul(f[i],(ll)i));
printf("%lld\n",ans);
return fflush(stdout),fclose(stdin),fclose(stdout),0;
}
c
题面:
有一个 \(A\times B\times C\) 的立方体,操作 \(1\) 删掉 \(x\le a\wedge y\le b\) 的部分,操作 \(2\) 删掉 \(y\le a\wedge z\le b\) 的部分,操作 \(3\) 删掉 \(z\le a\wedge x\le b\) 的部分,求一共删了多少。
题解:
求立方体体积并,可以发现垂直 \(x\) 轴的截面的图形一定是类似于楼梯的形状,且随着 \(x\) 的减小,楼梯变大。
先算出操作 \(2\) 的矩形面积,可以通过单调队列维护。
接下来将操作 \(1\) 和操作 \(3\) 的 \(x\) 从大到小排序,然后扫描线,操作 \(1\) 和操作 \(3\) 相当于将双端队列的头和尾移动并修改面积。红色部分相当于操作 \(1\),操作 \(3\) 类似。
应为每个点最多进队出队一次,加上排序时间复杂度 \(\text O(n\log n)\) 。
代码
#include<cstdio>
#include<algorithm>
#include<vector>
template<typename T>inline void read(T&x){
x=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
typedef long long ll;
const int N=300005;
int n,cntq1,cntq2,head=1,tail;
ll A,B,C,ans,S;
struct Que1{
ll y,z;
bool operator<(const Que1&b){
return y^b.y?y<b.y:z<b.z;
}
}q1[N],a[N],stk[N];
struct Que2{
int type;
ll x,y,z;
bool operator<(const Que2&b){
return x>b.x;
}
}q2[N];
int main(){
read(n),read(A),read(B),read(C);
for(int i=1;i<=n;i++){
int type;
ll a,b;
read(type),read(a),read(b);
switch(type){
case 1:
q2[++cntq2]={type,a,b,C};
break;
case 2:
q1[++cntq1]={a,b};
break;
case 3:
q2[++cntq2]={type,b,B,a};
}
}
std::sort(q1+1,q1+cntq1+1),std::sort(q2+1,q2+cntq2+1);
for(int i=1;i<=cntq1;i++){
for(;tail&&a[tail].z<=q1[i].z;)tail--;
a[++tail]=q1[i];
}
for(int i=1;i<=tail;i++)S+=a[i].z*(a[i].y-a[i-1].y);
q2[0].x=A;
for(int i=1;i<=cntq2;i++){
ans+=S*(q2[i-1].x-q2[i].x);
if(q2[i].type==1){
int top=0;
for(;head<=tail&&q2[i].y>=a[head].y;)stk[++top]=a[head],head++;
if(head<=tail)stk[++top]={q2[i].y,a[head].z};
a[--head]={q2[i].y,q2[i].z};
ll SS=0;
for(int i=1;i<=top;i++)SS+=stk[i].z*(stk[i].y-stk[i-1].y);
S+=q2[i].y*q2[i].z-SS;
}
else{
int top=0;
for(;head<=tail&&q2[i].z>=a[tail].z;)stk[++top]=a[tail],tail--;
if(head<=tail)stk[++top]={a[tail].y,q2[i].z};
a[++tail]={q2[i].y,q2[i].z};
ll SS=0;
std::reverse(stk+1,stk+top+1);
for(int i=1;i<=top;i++)SS+=stk[i].z*(stk[i].y-stk[i-1].y);
S+=q2[i].y*q2[i].z-SS;
}
}
ans+=S*q2[cntq2].x,printf("%lld\n",ans);
return fflush(stdout),fclose(stdin),fclose(stdout),0;
}
标签:le,int,define,20240926,read,测试,include,mod
From: https://www.cnblogs.com/junjunccc/p/18433618