hihoCoder [Offer收割]编程练习赛3 D子矩阵求和
Posted miracevin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder [Offer收割]编程练习赛3 D子矩阵求和相关的知识,希望对你有一定的参考价值。
http://hihocoder.com/discuss/question/3005
声明一下:
n是和x一起的,m是和y一起的
x是横着的,y是纵着的,x往右为正,y往下为正
(非常反常规的定义)
性质好题
看起来无从下手。
两个关键性质:
证明挺显然的。画画图
同余方程exgcd即可
子矩阵和?
先算出(0,0)的,每次平移,加减一行一列前n或m个,
细节:
1.纵向要循环到n,横向循环到m
2.注意开long long
3.反常规的设定真讨厌
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^‘0‘) #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> // #define int long long using namespace std; typedef long long ll; template<class T>il void rd(T &x) char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch==‘-‘)&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x); template<class T>il void output(T x)if(x/10)output(x/10);putchar(x%10+‘0‘); template<class T>il void ot(T x)if(x<0) putchar(‘-‘),x=-x;output(x);putchar(‘ ‘); template<class T>il void prt(T a[],int st,int nd)for(reg i=st;i<=nd;++i) ot(a[i]);putchar(‘\\n‘); namespace Modulo const int mod=998244353; il int ad(int x,int y)return x+y>=mod?x+y-mod:x+y; il int sub(int x,int y)return ad(x,mod-y); il int mul(int x,int y)return (ll)x*y%mod; il void inc(int &x,int y)x=ad(x,y); il void inc2(int &x,int y)x=mul(x,y); il int qm(int x,int y=mod-2)int ret=1;while(y)if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;return ret; template<class ...Args>il int ad(const int a,const int b,const Args &...args) return ad(ad(a,b),args...); template<class ...Args>il int mul(const int a,const int b,const Args &...args) return mul(mul(a,b),args...); // using namespace Modulo; namespace Miracle ll n,m,P; ll exgcd(ll a,ll b,ll &x,ll &y) if(!b) x=1;y=0;return a; ll ret=exgcd(b,a%b,y,x); y-=(a/b)*x; return ret; ll ch(ll x) if(m<=x) return m*(m+1)/2; return x*(x+1)/2+(m-x)*x; ll cl(ll y) if(n<=y) return n*(n+1)/2; return y*(y+1)/2+(n-y)*y; // ll calc() ll ax,ay; int main() int t;rd(t); while(t--) rd(n);rd(m);rd(P); swap(n,m); ax=0;ay=0; ll S=0; for(reg d=1;d<=min(n,m);++d) S+=(ll)d*(1+m-d+n-d); ll ns=S; ll s0=n*m; ll k,x,g; g=exgcd(s0,P,x,k); x=(x%(P/g)+(P/g))%(P/g); for(reg i=1;i<=m;++i) ll tmp=P-(ns%P); // cout<<" ii -------- "<<i<<" : "<<ns<<endl; if(tmp%g==0) ll nx=x*(tmp/g); nx=(nx%(P/g)+(P/g))%(P/g); ll tx=1+nx,ty=i+nx; // cout<<" tx "<<tx<<" ty "<<ty<<" : "<<ns+nx*s0<<endl; if(!ax||(ax+ay>tx+ty)||((ax+ay==tx+ty)&&(tx<ax))) ax=tx;ay=ty; ns-=ch(i); ns+=ch(i+n); ns=S; for(reg j=1;j<=n;++j) ll tmp=P-(ns%P); // cout<<" J ----------"<<j<<" ns "<<ns<<endl; if(tmp%g==0) ll nx=x*(tmp/g); nx=(nx%(P/g)+(P/g))%(P/g); ll tx=j+nx,ty=1+nx; // cout<<" tx "<<tx<<" ty "<<ty<<" : "<<ns+nx*s0<<endl; if(!ax||(ax+ay>tx+ty)||((ax+ay==tx+ty)&&(tx<ax))) ax=tx;ay=ty; ns-=cl(j); ns+=cl(j+m); if(!ax) puts("-1"); else printf("%lld %lld\\n",ax,ay); return 0; signed main() Miracle::main(); return 0; /* Author: *Miracle* */
矩阵非常对称,
这个性质挖的好啊。
然后就比较简单了。
以上是关于hihoCoder [Offer收割]编程练习赛3 D子矩阵求和的主要内容,如果未能解决你的问题,请参考以下文章
hihocoder offer收割编程练习赛12 C 矩形分割
hihocoder offer收割编程练习赛13 D 骑士游历
hihocoder offer收割编程练习赛11 B 物品价值