Problem A Flying Squirrel
设区间最大值的下标是,那么区间被划分为了左区间和右区间。左右区间不可达,相当于是划分。
如果每个区间内只有一个最大值,那么这其实是一个类似于线段树的东西。
但是因为可能有多个相同的最大值,所以其实是个分层图。不严格地说,每个节点既可以有多个父亲,又可以有多个儿子。
每个区间内相同的最大值深度相同,进行划分即可。
时,答案是子树内部的深度最大值减去的深度。
时,如果之间没有大于等于的柱子,也就是可以到达。那么答案就是两者深度差的绝对值。
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1e5 + 10 ;
int n , q ;
int a[maxn] ; //区间最大值对应的下标
int st[maxn][25] ;
void init()
{
for(int i = 1 ; i <= n ; i ++) st[i][0] = i ;
for(int j = 1 ; j <= 20 ; j ++)
for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++)
if(a[st[i][j - 1]] >= a[st[i + (1 << (j - 1))][j - 1]])
st[i][j] = st[i][j - 1] ;
else st[i][j] = st[i + (1 << (j - 1))][j - 1] ;
}
int query(int l,int r)
{
int len = log2(r - l + 1) ;
if(a[st[l][len]] >= a[st[r - (1 << len) + 1][len]]) return st[l][len] ;
else return st[r - (1 << len) + 1][len] ;
}
int ans[maxn] ;
int dep[maxn] ;
vector<int> p ;
void dfs(int l , int r , int val , int d)
{
if(l > r) return ;
int id = query(l , r) ;
if(a[id] != val) return ;
p.push_back(id) ;
dep[id] = d ;
dfs(l , id - 1 , val , d) ;
dfs(id + 1 , r , val , d) ;
}
int solve(int l , int r , int d)
{
int res = d ;
int id = query(l , r) ;
p.clear() ;
dfs(l , r , a[id] , d) ;
vector<int> pos = p ;
int siz = pos.size() ;
if(dep[l] == 0)
{
int t = pos[0] ;
int tmp = solve(l , t - 1 , d + 1) ;
res = max(res , tmp) ;
ans[t] = max(ans[t] , tmp - d) ;
}
if(dep[r] == 0)
{
int t = pos[siz - 1] ;
int tmp = solve(t + 1 , r , d + 1) ;
res = max(res , tmp) ;
ans[t] = max(ans[t] , tmp - d) ;
}
for(int i = 0 ; i + 1 < siz ; i ++)
{
int now = pos[i] ;
int nxt = pos[i + 1] ;
if(now + 1 == nxt) continue ;
int tmp = solve(now + 1 , nxt - 1 , d + 1) ;
res = max(res , tmp) ;
ans[now] = max(ans[now] , tmp - d) ;
ans[nxt] = max(ans[nxt] , tmp - d) ;
}
return res ;
}
void init2()
{
solve(1 , n , 1) ;
}
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
cin >> n >> q ;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] ;
init() ;
init2() ;
//for(int i = 1 ; i <= n ; i ++) cout << i << ' ' << dep[i] << ' ' << ans[i] << '\n' ;
while(q --)
{
int l , r ;
cin >> l >> r ;
if(r == 0) cout << ans[l] << '\n' ;
else
{
if(dep[l] > dep[r]) swap(l , r) ;
if(dep[l] == dep[r]) cout << "0\n" ;
else if(l < r)
{
int id = query(l + 1 , r) ;
if(dep[id] <= dep[l]) cout << "0\n" ;
else cout << dep[r] - dep[l] << '\n' ;
}
else
{
int id = query(r , l - 1) ;
if(dep[id] <= dep[l]) cout << "0\n" ;
else cout << dep[r] - dep[l] << '\n' ;
}
}
}
return 0 ;
}
Problem B Grid Coloring
留坑。
Problem C Evolution Game
按照的大小升序排列。
且两者的数量不超过。。
#include<bits/stdc++.h>
using namespace std ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int n , w ;
cin >> n >> w ;
vector<pair<int , int>> v(n + 1) ;
for(int i = 1 ; i <= n ; i ++)
{
int h ;
cin >> h ;
v[i] = {h , i} ;
}
sort(v.begin() + 1 , v.end()) ;
vector<int> dp(n + 1 , 0) ;
for(int i = 2 ; i <= n ; i ++)
for(int j = 1 ; j < i ; j ++)
if(abs(v[j].second - v[i].second) <= w && v[j].first < v[i].first)
dp[i] = max(dp[i] , dp[j] + 1) ;
cout << *max_element(dp.begin() + 1 , dp.end()) ;
return 0 ;
}
Problem D Bus Stop
从左往右扫,扫到时,如果的范围内没有,那么在的位置安装一个。
#include<bits/stdc++.h>
using namespace std ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int T ;
cin >> T ;
while(T --)
{
int n ;
cin >> n ;
vector<int> a(n + 1) ;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] ;
int lst = -100000 ;
int ans = 0 ;
for(int i = 1 ; i <= n ; i ++)
{
if(abs(a[i] - lst) <= 10) continue ;
else lst = a[i] + 10 , ans ++ ;
}
cout << ans << '\n' ;
}
return 0 ;
}
Problem E How many groups
本来写了多行的分类讨论,虽然过了,不过很不爽。
看了别人代码发现是个简单,感觉失去了一个亿。
分类讨论。
#include<bits/stdc++.h>
using namespace std ;
int n ;
int a[105] ;
int l[105] ;
int r[105] ;
int c[2] = {-1 , 1} ;
int d[4] = {-1 , 1 , 0 , 0} ;
int e[4] = {0 , 0 , -1 , 1} ;
int cal1(int i)
{
int res = 1 ;
if(i - 1 >= 1 && abs(a[i - 1] - a[i]) <= 2) res += ((i - 1) - l[i - 1] + 1) ;
if(i + 1 <= n && abs(a[i + 1] - a[i]) <= 2) res += (r[i + 1] - (i + 1) + 1) ;
return res ;
}
int cal2(int i , int j)
{
if(abs(a[i] - a[j]) > 2) return 0 ;
int res = 2 ;
if(i - 1 >= 1 && abs(a[i - 1] - a[i]) <= 2) res += ((i - 1) - l[i - 1] + 1) ;
if(j + 1 <= n && abs(a[j + 1] - a[j]) <= 2) res += (r[j + 1] - (j + 1) + 1) ;
return res ;
}
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int T ;
cin >> T ;
for(int cas = 1 ; cas <= T ; cas ++)
{
cout << "Case " << cas << ": " ;
cin >> n ;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] ;
sort(a + 1 , a + n + 1) ;
int ans = 0 ;
for(int i = 1 ; i <= n ; i ++)
{
int j = i ;
while(j + 1 <= n && a[j + 1] - a[j] <= 2) j ++ ;
for(int k = i ; k <= j ; k ++) l[k] = i , r[k] = j ;
ans = max(ans , j - i + 1) ;
i = j ;
}
for(int i = 1 ; i <= n ; i ++)
{
int tmp = a[i] ;
for(int j = 0 ; j < 2 ; j ++)
{
a[i] = tmp + c[j] ;
ans = max(ans , cal1(i)) ;
}
a[i] = tmp ;
}
for(int i = 1 ; i <= n - 1 ; i ++)
{
int tmp1 = a[i] ;
int tmp2 = a[i + 1] ;
for(int j = 0 ; j < 2 ; j ++)
for(int k = 0 ; k < 2 ; k ++)
{
a[i] = tmp1 + c[j] ;
a[i + 1] = tmp2 + c[k] ;
ans = max(ans , cal2(i , i + 1)) ;
}
a[i] = tmp1 ;
a[i + 1] = tmp2 ;
}
//cout << ans << '\n' ;
for(int i = 1 ; i <= n ; i ++)
{
int res = 1 ;
a[i] ++ ;
if(i + 1 <= n)
{
if(i - 1 >= 1 && abs(a[i] - a[i - 1]) <= 2) res += (i - 1) - l[i - 1] + 1 ;
ans = max(ans , res) ;
if(abs(a[i] - a[i + 1]) <= 2)
{
res += r[i + 1] - (i + 1) + 1 ;
ans = max(ans , res) ;
int nxt = r[i + 1] ;
//cout << nxt << '\n' ;
if(nxt + 1 <= n)
{
int tmp1 = a[nxt] ;
int tmp2 = a[nxt + 1] ;
for(int j = 0 ; j < 4 ; j ++)
{
a[nxt] = tmp1 + d[j] ;
a[nxt + 1] = tmp2 + e[j] ;
int tt = res ;
if(abs(a[nxt] - a[nxt + 1]) <= 2)
{
if(abs(a[nxt] - a[nxt - 1]) <= 2)
{
tt ++ ;
//cout << res << '\n' ;
if(nxt + 2 <= n && abs(a[nxt + 1] - a[nxt + 2]) <= 2)
{
tt += r[nxt + 2] - (nxt + 2) + 1 ;
}
ans = max(ans , tt) ;
}
}
}
a[nxt] = tmp1 ;
a[nxt + 1] = tmp2 ;
}
}
}
a[i] -- ;
res = 1 ;
a[i] -- ;
if(i + 1 <= n)
{
if(i - 1 >= 1 && abs(a[i] - a[i - 1]) <= 2) res += (i - 1) - l[i - 1] + 1 ;
ans = max(ans , res) ;
if(abs(a[i] - a[i + 1]) <= 2)
{
res += r[i + 1] - (i + 1) + 1 ;
ans = max(ans , res) ;
int nxt = r[i + 1] ;
//cout << nxt << '\n' ;
if(nxt + 1 <= n)
{
int tmp1 = a[nxt] ;
int tmp2 = a[nxt + 1] ;
for(int j = 0 ; j < 4 ; j ++)
{
a[nxt] = tmp1 + d[j] ;
a[nxt + 1] = tmp2 + e[j] ;
int tt = res ;
if(abs(a[nxt] - a[nxt + 1]) <= 2)
{
if(abs(a[nxt] - a[nxt - 1]) <= 2)
{
tt ++ ;
//cout << res << '\n' ;
if(nxt + 2 <= n && abs(a[nxt + 1] - a[nxt + 2]) <= 2)
{
tt += r[nxt + 2] - (nxt + 2) + 1 ;
}
ans = max(ans , tt) ;
}
}
}
a[nxt] = tmp1 ;
a[nxt + 1] = tmp2 ;
}
}
}
a[i] ++ ;
}
//cout << ans << '\n' ;
for(int i = 1 ; i <= n ; i ++)
{
a[i] -- ;
int res = 1 ;
if(i - 1 >= 1)
{
if(i + 1 <= n && abs(a[i] - a[i + 1]) <= 2) res += r[i + 1] - (i + 1) + 1 ;
ans = max(ans , res) ;
if(abs(a[i] - a[i - 1]) <= 2)
{
res += (i - 1) - l[i - 1] + 1 ;
ans = max(ans , res) ;
int nxt = l[i - 1] ;
if(nxt - 1 >= 1)
{
int tmp1 = a[nxt] ;
int tmp2 = a[nxt - 1] ;
for(int j = 0 ; j < 4 ; j ++)
{
int tt = res ;
a[nxt] = tmp1 + d[j] ;
a[nxt - 1] = tmp2 + e[j] ;
if(abs(a[nxt] - a[nxt - 1]) <= 2)
{
if(abs(a[nxt] - a[nxt + 1]) <= 2)
{
tt ++ ;
if(nxt - 2 >= 1 && abs(a[nxt - 1] - a[nxt - 2]) <= 2)
{
tt += (nxt - 2) - l[nxt - 2] + 1 ;
}
ans = max(ans , tt) ;
}
}
}
a[nxt] = tmp1 ;
a[nxt - 1] = tmp2 ;
}
}
}
a[i] ++ ;
a[i] ++ ;
res = 1 ;
if(i - 1 >= 1)
{
if(i + 1 <= n && abs(a[i] - a[i + 1]) <= 2) res += r[i + 1] - (i + 1) + 1 ;
ans = max(ans , res) ;
if(abs(a[i] - a[i - 1]) <= 2)
{
res += (i - 1) - l[i - 1] + 1 ;
ans = max(ans , res) ;
int nxt = l[i - 1] ;
if(nxt - 1 >= 1)
{
int tmp1 = a[nxt] ;
int tmp2 = a[nxt - 1] ;
for(int j = 0 ; j < 4 ; j ++)
{
int tt = res ;
a[nxt] = tmp1 + d[j] ;
a[nxt - 1] = tmp2 + e[j] ;
if(abs(a[nxt] - a[nxt - 1]) <= 2)
{
if(abs(a[nxt] - a[nxt + 1]) <= 2)
{
tt ++ ;
if(nxt - 2 >= 1 && abs(a[nxt - 1] - a[nxt - 2]) <= 2)
{
tt += (nxt - 2) - l[nxt - 2] + 1 ;
}
ans = max(ans , tt) ;
}
}
}
a[nxt] = tmp1 ;
a[nxt - 1] = tmp2 ;
}
}
}
a[i] -- ;
}
cout << ans << '\n' ;
}
return 0 ;
}
表示前个数修改了次且第个数是的以为右端点的最大连续段长度。
#include<bits/stdc++.h>
using namespace std ;
int n , a[105] ;
int dp[105][3][3] ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int T ;
cin >> T ;
for(int cas = 1 ; cas <= T ; cas ++)
{
cout << "Case " << cas << ": " ;
cin >> n ;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] ;
sort(a + 1 , a + n + 1) ;
for(int i = 0 ; i <= n ; i ++)
for(int j = 0 ; j <= 2 ; j ++)
for(int k = 0 ; k <= 2 ; k ++)
dp[i][j][k] = -1e9 ;
int fix = 1 ;
for(int i = 1 ; i <= n ; i ++)
{
dp[i][0][fix + 0] = 1 ;
dp[i][1][fix - 1] = 1 ;
dp[i][1][fix + 1] = 1 ;
}
for(int i = 1 ; i < n ; i ++)
for(int j = 0 ; j <= 2 ; j ++)
for(int k = 0 ; k <= 2 ; k ++)
for(int p = j ; p <= 2 ; p ++)
for(int t = 0 ; t <= 2 ; t ++)
{
if(dp[i][j][k] < 0) continue ;
int now = a[i] + k - fix ;
int nxt = a[i + 1] + t - fix ;
if(abs(now - nxt) <= 2 && (j + abs(t - fix)) == p)
{
dp[i + 1][p][t] = max(dp[i + 1][p][t] , dp[i][j][k] + 1) ;
}
}
int ans = 0 ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 0 ; j <= 2 ; j ++)
for(int k = 0 ; k <= 2 ; k ++)
ans = max(ans , dp[i][j][k]) ;
cout << ans << '\n' ;
}
return 0 ;
}
Problem F Lucky Pascal Triangle
求满足的和的对数
库默尔定理:中p的幂次为n+m在p进制下进位次数,p为质数
题目可以转化为求n-m和m在7进制下产生了进位的对数
数位dp:表示从高到低考虑到第i位,已经产生了j个进位,是否有大小限制,是否强制下一位产生进位的方案数
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int p = 7, mod = 1e9 + 7;
int kas;
ll n;
int a[25], len;
int f[25][2][2][2];
inline void Add(int &x, int y) { x += y; if(x>=mod) x -= mod; }
void change(ll n)
{
len = 0;
while(n)
{
a[len++] = n%p;
n /= p;
}
}
int count(int x)
{
if(x<p) return (1ll*(x+1)*(x+2)>>1)%mod;
x = 2*p - 2 - x;
return (1ll*p*p-(1ll*(x)*(x+1)>>1))%mod;
}
int cal(int l, int r) { return (count(r)-count(l-1)+mod)%mod; }
void solve()
{
scanf("%lld", &n);
change(n);
for(int i=0; i<=len; i++) memset(f[i], 0, sizeof(f[i]));
f[len][0][1][0] = 1;
for(int i=len; i; i--)
for(int j=0; j<2; j++)
for(int lim=0; lim<2; lim++)
for(int d=0; d<2; d++) if(f[i][j][lim][d])
for(int nxtd=0; nxtd<2; nxtd++)
{
int l = d*p - nxtd, r = (lim ? a[i-1] : p-1) + l;
if(lim) Add(f[i-1][j|nxtd][0][nxtd], 1ll*f[i][j][1][d]*cal(l, r-1)%mod), Add(f[i-1][j|nxtd][1][nxtd], 1ll*f[i][j][1][d]*cal(r, r)%mod);
else Add(f[i-1][j|nxtd][0][nxtd], 1ll*f[i][j][0][d]*cal(l, r)%mod);
}
int ans = (f[0][1][0][0] + f[0][1][1][0])%mod;
printf("Case %d: %d\n", ++kas, ans);
}
int main()
{
int _; scanf("%d", &_);
while(_--) solve();
return 0;
}
Problem G Communication
题面的英语写的过于上等。没说是可传递的,然后写了个并查集果然了。
反应过来如果可以传递就是一个,贴个板子就过了。
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 200 + 10 ;
const int maxm = 10000 + 10 ;
int n ;
struct Link
{
int num , head[maxn] ;
struct Edge
{
int v , next ;
} edge[maxm << 1] ;
void init()
{
num = 0 ;
memset(head , -1 , sizeof(head)) ;
}
void add_edge(int u , int v)
{
edge[num].v = v ;
edge[num].next = head[u] ;
head[u] = num ++ ;
}
} link ;
struct Tarjan
{
int cnt , scc_num , lay ;
int low[maxn] , dfn[maxn] , belong[maxn] ;
int st[maxn] , s[maxn] ;
bool vis[maxn] ;
void init()
{
cnt = scc_num = lay = 0 ;
memset(vis , 0 , sizeof(vis)) ;
memset(low , 0 , sizeof(low)) ;
memset(dfn , 0 , sizeof(dfn)) ;
}
void dfs(int k)
{
vis[k] = 1 ;
low[k] = dfn[k] = ++ lay ;
st[++ cnt] = k ;
for(int i = link.head[k] ; i != -1 ; i = link.edge[i].next)
{
int v = link.edge[i].v ;
if(dfn[v] == 0)
{
dfs(v) ;
low[k] = min(low[k] , low[v]) ;
}
else if(vis[v])
low[k] = min(low[k] , dfn[v]) ;
}
if(dfn[k] == low[k])
{
++ scc_num ;
do
{
belong[st[cnt]] = scc_num ;
vis[st[cnt]] = 0 ;
cnt -- ;
} while(st[cnt + 1] != k) ;
}
}
void cal()
{
for(int i = 1 ; i <= n ; i ++)
if(dfn[i] == 0) dfs(i) ;
}
} tarjan ;
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
int T ;
cin >> T ;
while(T --)
{
cin >> n ;
link.init() ;
tarjan.init() ;
int e ;
cin >> e ;
for(int i = 1 ; i <= e ; i ++)
{
int u , v ;
cin >> u >> v ;
u ++ ;
v ++ ;
link.add_edge(u , v) ;
}
tarjan.cal() ;
cout << tarjan.scc_num << '\n' ;
}
return 0 ;
}
Problem H As rich as Crassus
留坑。
Problem I Bowabowaukulipukuli
留坑。
Problem J Floating-Point Hazard
需要看出来这是求导定义式的分子。
,求导后得到。
答案是。
#include<bits/stdc++.h>
using namespace std ;
#define ld long double
int main()
{
std::ios::sync_with_stdio(false) , cin.tie(0) ;
while(1)
{
int l , r ;
scanf("%d%d" , &l , &r) ;
if(l == 0 && r == 0) break ;
ld ans = 0 ;
for(int i = l ; i <= r ; i ++) ans += pow(i , -2.0 / 3.0) ;
ans /= 3.0 ;
int res = 15 ;
while(ans >= 10.0) ans /= 10 , res -- ;
while(ans < 1.0) ans *= 10 , res ++ ;
printf("%.5LfE-" , ans) ;
printf("%03d\n" , res) ;
}
return 0 ;
}
Problem K The Stream of Corning 2
裸的第大。
#include <bits/stdc++.h>
#define all(x) begin(x), end(x)
using namespace std;
const int N = 1e5 + 5;
const int MAXSIZE = 1 << 20;
char buf[MAXSIZE], *p1, *p2;
inline char gc() { return (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin),p1==p2) ? EOF : *p1++); }
inline void read(int& t)
{
t = 0; char c = gc();
while(c>'9'||c<'0') c = gc();
while(c>='0'&&c<='9') t = t*10 + c - 48, c = gc();
}
bool qry[N];
int kas;
int n, ans[N];
struct Event
{
int t, v, op;
bool operator < (const Event& oth) { return t==oth.t ? op<oth.op : t<oth.t; }
}e[N<<1];
struct seg
{
int l, r, cnt;
}t[N<<2];
void up(int p) { t[p].cnt = t[p<<1].cnt + t[p<<1|1].cnt; }
void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r, t[p].cnt = 0;
if(l==r) return;
int mid = (l+r)>>1;
build(p<<1, l, mid); build(p<<1|1, mid+1, r);
}
void upd(int p, int x, int v)
{
int l = t[p].l, r = t[p].r;
if(l==r)
{
t[p].cnt += v;
return;
}
int mid = (l+r) >> 1;
if(x<=mid) upd(p<<1, x, v);
else upd(p<<1|1, x, v);
up(p);
}
int ask(int p, int k)
{
int l = t[p].l, r = t[p].r;
if(l==r) return t[p].cnt>=k ? l : -1;
if(t[p<<1].cnt>=k) return ask(p<<1, k);
else return ask(p<<1|1, k-t[p<<1].cnt);
}
void solve()
{
read(n);
int m = 0;
vector<int> lsh;
auto getid = [&](int x) { return lower_bound(all(lsh), x) - begin(lsh) + 1; };
for(int i=1; i<=n; i++)
{
qry[i] = 0;
int op; read(op);
if(op==1)
{
int l, v, r; read(l), read(v), read(r);
e[++m] = {l, v, 1};
e[++m] = {r+1, v, -1};
lsh.push_back(v);
}
else
{
qry[i] = 1;
int t, k; read(t), read(k);
e[++m] = {t, k, i+1};
}
}
sort(all(lsh));
lsh.resize(unique(all(lsh)) - begin(lsh));
build(1, 1, (int)lsh.size());
sort(e+1, e+m+1);
for(int i=1; i<=m; i++)
{
if(e[i].op<=1) upd(1, getid(e[i].v), e[i].op);
else ans[e[i].op-1] = ask(1, e[i].v);
}
printf("Case %d:\n", ++kas);
for(int i=1; i<=n; i++)
if(qry[i])
{
if(ans[i]==-1) puts("-1");
else printf("%d\n", lsh[ans[i]-1]);
}
}
int main()
{
int _; read(_);
while(_--) solve();
return 0;
}
Problem L Largest Allowed Area
看作二维平面上的点,在斜率是的直线上进行双指针扫描,以作为左上角的点,作为右下角的点。前缀和预处理后可以判断正方形内的个数。
不过这题卡常,需要快读。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5, inf = 1e9;
int n, m;
int a[N][N], r[N][N], s[N][N];
int qry(int x1, int y1, int x2, int y2) { return s[x2][y2]+s[x1-1][y1-1]-s[x2][y1-1]-s[x1-1][y2]; }
inline void read(int& t)
{
t = 0;
char c = getchar();
while(c>'9'||c<'0') c = getchar();
while(c>='0'&&c<='9') t = t*10 + c - 48, c = getchar();
}
void solve()
{
read(n), read(m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++) read(a[i][j]), s[i][j] = s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];
for(int i=0; i<=n; i++)
for(int j=0; j<=m; j++) r[i][j] = i;
int ans = 0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
int rgt = r[i-1][j-1];
while(rgt+1<=i && qry(rgt+1, rgt+1+j-i, i, j)>1) rgt++;
ans = max(ans, i-rgt);
r[i][j] = rgt;
}
}
printf("%d\n", ans);
}
int main()
{
int _; read(_);
while(_--) solve();
return 0;
}