cf 526 F

CF 526F

一个N × N的地图上有N个棋子,每一行每一列都有且仅有一个 棋子。问有多少个正方形满足其内部的棋子数等于其边长

SOLUTION:

可以发现按x坐标把点排序后得出一个排列,求有多少个区间长度等于最大值减最少值。可以考虑分治,可以算出中心到左右区间的最大最小值,若最大最小值在同侧则可以枚举一端算出另一端再判断是否合法。若不同侧可以发现左最大右最小时r-l==max[l]-min[r],即l+max[l]==r+min[r],相互独立可以开桶判断。从中间往左枚举一端,发现满足左最大右最小的右端区间是单调的,因为最大值单调上升最小值单调下降,左端最大最小值变化,右端最小值必须更小最大值可以更大,判一下是否有答案即可。(转载自chunkitlau)

仍然是注意细节,想清楚再写,尽量少犯错

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 300020
 7 #define inf 0x3f3f3f3f
 8 
 9 typedef long long ll;
10 int a[maxn],mx[maxn],mn[maxn],n,num[maxn];
11 ll ans;
12 
13 void solve(int l,int r){
14     if ( l == r ) return;
15     int mid = (l + r) >> 1;
16     //========================mx和mn在mid两侧
17     mx[mid] = mn[mid] = a[mid] , mx[mid + 1] = mn[mid + 1] = a[mid + 1];
18     for (int i = mid + 2 ; i <= r ; i++){
19         mn[i] = min(mn[i - 1],a[i]);
20         mx[i] = max(mx[i - 1],a[i]);
21     }
22     for (int i = mid - 1 ; i >= l ; i--){
23         mn[i] = min(mn[i + 1],a[i]);
24         mx[i] = max(mx[i + 1],a[i]);
25     }
26     //注意加减1的细节
27     for (int i = mid,j = mid + 1,k = mid + 1 ; i >= l ; i--){
28         while ( k <= r && mx[i] >= mx[k] ) num[k - mid + mn[k]]++ , k++;
29         while ( j <= min(k - 1,r) && mn[i] < mn[j] ) num[j - mid + mn[j]]-- , j++;
30         if ( j > r ) break;
31         if ( mx[i] + 1 >= mid - i + 1  ) ans += num[mx[i] + 1 - (mid - i + 1)];
32     }    
33     for (int i = mid + 1 ; i <= r ; i++) num[i - mid + mn[i]] = 0;
34 
35     
36     for (int i = mid + 1 , j = mid , k = mid ; i <= r ; i++){
37         while ( k >= l && mx[i] >= mx[k] ) num[mid - k + 1 + mn[k]]++ , k--;
38         while ( j >= max(l,k + 1) && mn[i] < mn[j] ) num[mid - j + 1 + mn[j]]-- , j--;
39         if ( j < l ) break;
40         if ( mx[i] + 1 >= i - mid ) ans += num[mx[i] + 1 - (i - mid)];
41     }
42     for (int i = l ; i <= mid ; i++) num[mid - i + 1 + mn[i]] = 0;
43     //========================mx和mn在mid同侧
44     for (int i = mid ; i >= l ; i--){
45         int x = mx[i] - mn[i] + i;
46         if ( x <= r && x > mid && mx[x] <= mx[i] && mn[x] >= mn[i] ) ans++;
47     }
48     for (int i = mid + 1 ; i <= r ; i++){
49         int x = i - (mx[i] - mn[i]);
50         if ( x >= l && x <= mid && mx[x] <= mx[i] && mn[x] >= mn[i] ) ans++;
51     }
52     solve(l,mid) , solve(mid + 1,r);
53 }
54 int main(){
55     freopen("input.txt","r",stdin);
56     scanf("%d",&n);
57     for (int i = 1 ; i <= n ; i++){
58         int x,y;
59         scanf("%d %d",&x,&y);
60         a[x] = y;
61     }
62     solve(1,n);
63     printf("%lld\n",ans + n);
64     return 0;
65 }
View Code

猜你喜欢

转载自www.cnblogs.com/zqq123/p/9249653.html