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 ",ans + n); 64 return 0; 65 }