hihocoder1286 : 子矩阵求和

http://hihocoder.com/problemset/problem/1286

题解

NB分析题。

首先我们令\(s[i][j]\)表示以\((i,j)\)为左上角的矩形的权值和。

因为\(a[i][j]+1=a[i+1][j+1]\)

所以\(s[i][j]+n*m=s[i+1][j+1]\)

再有当\(i\geq m\)\(s[i][1]=s[i+1][1]\)

\(j\geq n\)\(s[1][i]=s[1][i+1]\)

那么我们若知道一个\((i,j)\)值,那么所有的\((i+x,j+x)\)中最小的合法解可以通过解同余方程求出。

根据发现的性质,只需要枚举\(n+m\)\((i,j)\)即可。

代码

#include<bits/stdc++.h>
#define N 200009
using namespace std;
typedef long long ll;
ll n,m,k;
ll dp[N];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct node{
    int x,y;
    inline bool operator <(const node &b)const{
        if(x+y!=b.x+b.y)return x+y<b.x+b.y;
        return x<b.x;
    }
}ans;
inline ll Sum(ll n){return n*(n+1)/2;}
inline ll sum(ll n,ll m){
    if(!n||!m)return 0;
    if(n>m)swap(n,m);
    return dp[n]*2-Sum(n)+(m-n)*Sum(n);
}
inline ll calc(ll x,ll y,ll n,ll m){
   return sum(x+n-1,y+m-1)-sum(x-1,y+m-1)-sum(x+n-1,y-1)+sum(x-1,y-1);
}
inline void prework(ll n){
    for(int i=1;i<=n;++i)dp[i]=dp[i-1]+1ll*i*(i+1)/2;
}
ll xx,yy,g;
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
void exgcd(ll a,ll b){
    if(!b){
      xx=1;yy=0;
      return;
    }
    exgcd(b,a%b);
    ll k=xx;
    xx=yy;
    yy=k-(a/b)*yy;
}
inline int solve(ll x,ll y,ll k){
    x%=k;y%=k;
    x=k-x;
    if(x%g)return -1;
    ll o=(xx*(x/g)%(k/g)+(k/g))%(k/g);
    return o;
}
int main(){
    int Q=rd();
    prework(200000);
    while(Q--){
        n=rd();m=rd();k=rd();
        g=gcd(1ll*n*m%k,k);
        exgcd(1ll*n*m%k,k);/
        bool tag=0;
        int aa=1e9;
        ans=node{aa,aa};
        for(int i=1;i<=n;++i){
            int x=solve(calc(1,i,n,m),1ll*n*m,k);
            if(x!=-1){
                tag=1;
                node du=node{1+x,i+x};
                if(du<ans)ans=du;
            }
        }
        for(int i=1;i<=m;++i){
            int x=solve(calc(i,1,n,m),1ll*n*m,k);
            if(x!=-1){
                tag=1;
                node du=node{i+x,1+x};
                if(du<ans)ans=du;;
            }
        }
        if(tag){
          printf("%d %d\n",ans.x,ans.y);
        }
        else puts("-1");
    }
    return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/11039433.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值