• 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
    ",ans + n);
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    2019/2/3从字符串中删除指定的字符
    2019/2/3求组合数
    2019/2/3统计各成绩段的学生人数
    2019/2/3摄氏一华氏温度转换表
    2019/1/29有选择的复制字符串
    2019/1/28数字的移动
    2019/1/2810个整数的数据处理
    2019/1/27从三个数中找出最大的数(函数和宏)
    2019/1/23编写函数统计字符串中字母、数字、空格和其它字符的个数
    Jenkins 执行python脚本
  • 原文地址:https://www.cnblogs.com/zqq123/p/9249653.html
Copyright © 2020-2023  润新知