题目大意:
给定 n、m、k,可以确定一个n行m列的二维矩阵 a
,并且这个矩阵,a[i][j]=i*j/gcd(i,j)
,求在这个矩阵中所有的大小为k矩阵的最大值的和
两种方法:
- 单调队列,可以用deque也可以用数组模拟,维护k范围中每一列的最大值和每一行的最大值,最后求解
- dfs,因为每个点的值都是确定的,可以直接从
a[k][k]
开始搜,找到一个小矩阵的最大值后,再找另外一个的,当然如果k==1的话,就不需要搜了
单调队列法
#include<iostream>
#include<algorithm>
#include<deque>
using namespace std;
#define ll long long
const int N = 5e3+5;
int a[N][N],b[N][N];
int gcd(int a,int b){return b>0? gcd(b,a%b):a;}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m,n,k;
ll ans=0;
deque<int> q;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j] = i*j/gcd(i,j);
for(int i=1;i<=n;i++)
{
q.clear();
for(int j=1;j<=m;j++)
{
while (q.size()&&q.front()<=j-k) q.pop_front(); //队头的下标超出k个就弹出
while (q.size()&&a[i][q.back()]<=a[i][j]) q.pop_back();//如果队尾的元素比当前还小弹出
q.push_back(j);
b[i][j] = max(b[i][j],a[i][q.front()]); //确定当前列K范围内的最大值
}
}
for(int j=k;j<=m;j++) //直接从第k开始找就行了
{
q.clear();
for(int i=1;i<=n;i++)
{
while (q.size()&&q.front()<=i-k) q.pop_front();
while (q.size()&&b[q.back()][j]<=b[i][j]) q.pop_back();
q.push_back(i);
if(i>=k) ans+=b[q.front()][j];
}
}
cout<<ans<<endl;
}
DFS方法
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N=5e3+5;
int dp[N][N];
int gcd(int a,int b){ //最大公因数
return b>0?gcd(b,a%b):a;
}
int dfs(int x,int y){
int a,b;
if(gcd(x,y)==1) return x*y; //如果最大公因数是1,则此时一定是最大值
else{
a=dfs(x-1,y); //向左
b=dfs(x,y-1); //向上
}
return max(a,b); //返回最大值
}
int main(){
int n,m,k;
ll ans=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=k;i<=n;i++){
for(int j=k;j<=m;j++){
if(k==1) ans+=(i*j)/gcd(i,j);
else ans+=dfs(i,j);
}
}
printf("%lld\n",ans);
return 0;
}