【hiho一下 第146周】子矩阵求和
2017-10-04 18:44
288 查看
【题目链接】:http://hihocoder.com/contest/hiho146/problem/1
【题意】
【题解】
设s[i][j]表示左上角的坐标为(i,j)的n*m的矩阵的和;
有s[i][j]=s[i-1][j-1]+n*m;
不信自己看;
而且
对于i>=max(n,m)
s[i][j]=s[i+1][j];
对于j>=max(n,m)
s[i][j]=s[i][j+1];
而每一行从左到右的元素和;
每一列从上刀下的元素的和是有规律的;
就是前x个数是等差,后面全都相等;
然后根据这个
我们只要算出
s[1][1..max(n,m)]
和s[1..max(n,m)][1]
然后算出这2*max(n,m)个对角线上的各个位置作为左上角的矩阵的和就好;
当然不能强算了;
根据
s[i][j]=s[i-1][j-1]+n*m;
我们知道
s[i][j]之后;
相当于要求最小的x
使得
(s[i][j]+x*n*m%k)==0
这里我们可以预处理出最小的使得x*n*m%k==t的x;
记录下每个t对应的x就好;(当然有一些t可能没办法得到);
这样根据s[1][1..max(n,m)]和s[1..max(n,m)][1]算出每个对角线上有没有可能有有符合要求的点;
每次往下走的时候只会改变一行或一列的和;
所以可以做到O(1)算出来;
【Number Of WA】
17
【完整代码】
#include <bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define LL long long #define rep1(i,a,b) for (int i = a;i <= b;i++) #define rep2(i,a,b) for (int i = a;i >= b;i--) #define mp make_pair #define pb push_back #define fi first #define se second #define ms(x,y) memset(x,y,sizeof x) typedef pair<int,int> pii; typedef pair<LL,LL> pll; const int dx[9] = {0,1,-1,0,0,-1,-1,1,1}; const int dy[9] = {0,0,0,-1,1,-1,1,-1,1}; const double pi = acos(-1.0); const int N = 110; const int K = 1e6+100; int n,m,k,need[K],px,py; void pre() { ms(need,-1); LL now = 0;int x = 0; while (need[now]==-1) { need[now] = x; now = (now+1LL*n*m)%k; x++; } } int get_sum(int idx,int len) { if (len<=idx) return (1LL*(1+len)*len/2)%k; else return (1LL*(1+idx)*idx/2 + 1LL*(len-idx)*idx)%k; } void gengxin(int x,int y) { if (px==-1 && py==-1) { px = x,py = y; return; } if (x+y<px+py) { px = x,py = y; } else if (x+y==px+py && x<px) { px = x,py = y; } } int main() { //freopen("F:\\rush.txt","r",stdin); ios::sync_with_stdio(false); int Q; cin >> Q; while (Q--) { px=-1,py=-1; cin >> n >> m >> k; pre(); //左上角n行m列的矩阵和 LL sum = 0,tsum; rep1(i,1,m) sum=(sum+get_sum(i,n))%k;//相当于加上第i列的n行元素 tsum = sum; int ma = max(m,n); rep1(nowy,1,ma) { int t = (k-sum)%k; if (need[t]!=-1) gengxin(1+need[t],nowy+need[t]); sum=(sum-get_sum(nowy,n)+k+get_sum(nowy+m,n))%k; } sum = tsum; rep1(nowx,1,ma) { int t = (k-sum)%k; if (need[t]!=-1) { int x = nowx+need[t],y = 1+need[t]; gengxin(x,y); } sum=(sum-get_sum(nowx,m)+k+get_sum(nowx+n,m))%k; } if (px==-1) cout <<-1<<endl; else cout <<px <<' '<<py<<endl; } //printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC); return 0; }
相关文章推荐
- hiho一下 第五十七周 高斯消元·二(高斯消元解异或方程组)
- hihocoder第57周hiho一下#1196 : 高斯消元·二
- hiho一下第56周 高斯消元
- hiho一下 第六十周 题目1 : String Matching Content Length dp 最长公共子序列
- hiho一下 第六十一周 题目1 : Combination Lock 线段树 成段更新
- hiho一下第133周 2-SAT·hihoCoder音乐节(2-SAT)(强连通)
- hiho一下 第六十三周
- hiho一下 第119周 #1398 : 网络流五·最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】
- (hiho一下第三周)#1015 KMP算法 【模版】
- hiho一下-第104周-平衡树·Splay
- hiho一下第二周 Trie树
- hiho一下 第150周 Demo Day
- hiho一下 第九十一周 Events Arrangement
- hiho一下 第九十二周 数论一·Miller-Rabin质数测试
- hiho一下第一周#1032 : 最长回文子串
- 二维树状数组--子矩阵求和
- hiho一下 第十四周(并查集)
- hiho一下 第三周---KMP算法
- hiho一下,第163周 题目1 : 希尔伯特曲线
- hiho一下 第166周 逃离迷宫