hdu 5101 单调+二分查找

因为每次要找其他班和自己相加之和大于固定值的人数的个数,所以先排序,利用二分查找找到满足条件的最小值,然后后面的均符合条件,利用容斥定理中的补集关系,让总的排列中满足条件的个数-自己班中满足条件的个数=其他班满足条件的个数,二分查找自己写的,不熟悉的可以用stl里的upper_bound函数

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define MAX 1007
#define N 107

using namespace std;


int a[MAX][N];
int b[MAX*N];
int sum[MAX];

bool cmp ( int a , int b )
{
    return a > b;
} 

int get ( int v , int a[] , int len )
{
    int left = 1 , right = len , mid;
    while ( left < right )
    {
        mid = (left + right+1) >> 1;
        if ( a[mid] > v ) left = mid;
        else right = mid -1; 
    }
    if ( a[left] > v )
        return left; 
    else return 0;
}

int main ( )
{
    int t,n,k,iq;
    scanf ( "%d" , &t );
    while ( t-- )
    {
        scanf ( "%d%d" , &n , &k );
        long long ans = 0;
        int cnt = 1;
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d" , &sum[i] );
            for ( int j = 1 ; j <= sum[i] ; j++ )
            {
                scanf ( "%d" , &a[i][j] );
                b[cnt++] = a[i][j];
            }
            sort ( a[i]+1 , a[i]+sum[i]+1 , cmp );
        }
        sort ( b+1 , b+cnt , cmp );
        for ( int i = 1 ; i <= n ; i++ )
                for ( int j = 1 ; j <= sum[i] ; j++ )
                {
                  long long temp = get ( k-a[i][j] , b , cnt-1 );
                  temp -= get ( k-a[i][j] , a[i] , sum[i] );
                  ans += temp;
                }
        printf ( "%I64d\n" , ans/2 );
    }
}


你可能感兴趣的:(C++,二分查找)