2020牛客暑期多校训练营(第九场)

比赛链接

A

一、题意

二、题解

三、代码

B

看800遍题解没懂咋做

一、题意

二、题解

三、代码

C

不懂概率1/2怎么处理

一、题意

二、题解

三、代码

D

一、题意

二、题解

三、代码

E

一、题意

二、题解

三、代码

F

一、题意

有n天,每天有k_i个物品,权值a_i

从n天中选择m天,每天从该天的若干个权值中选择1个。

有m个权值,使这m个权值的最大值和最小值的差值最小。

数据范围:1\leqslant a_i \leqslant 10^9 , 1\leqslant n\leqslant 10^6,\sum k_i \leqslant 2 \cdot 10^6 , k_i \geqslant 1

二、题解

每个物品有两个属性(权值,天数)。

选择m个物品,这些物品的天数两两不同。

把这些物品按权值从小到大排序,然后滑动窗口扫一遍,注意对窗口内的天数打标记,认为这些天数已经用过了。

然后取最小值就行了。

三、代码

#include
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << '*' << x << '\n'
#define ddebug(x , y)  cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair pii ;
typedef pair pll ;
const int mod = 998244353 ;
const int maxn = 2e6 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
mt19937  rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ; 
int n , m ;
struct node
{
    int x , id , p ;
    bool operator < (const node &s) const
    {
        if(x != s.x)  return x < s.x ;
        else if(id != s.id)  return x < s.id ;
        else  return p < s.p ;
    }
} b[maxn] ;
int cnt = 0 ;
bool vis[maxn] ;
int main()
{
    ios ;
    cin >> n >> m ;
    rep(i , 1 , n)
    {
        int k ;
        cin >> k ;
        rep(j , 1 , k)
        {
            int x ;
            cin >> x ;
            b[++ cnt] = (node){x , i , cnt} ;
        }
    }
    sort(b + 1 , b + cnt + 1) ;
    int ans = inf ;
    int l = 1 , r = 0 ;
    int num = 0 ;
    while(l < cnt)
    {
        while(num < m && r < cnt)
        {
            r ++ ;
            if(vis[b[r].id])  continue ;
            else
            {
                vis[b[r].id] = 1 ;
                num ++ ;
            }
        }
        if(num == m)  ans = min(ans , b[r].x - b[l].x) ;
        else  break ;
        while(num == m && l <= r)
        {
            if(!vis[b[l].id])  l ++ ;
            else
            {
                vis[b[l].id] = 0 ;
                l ++ ;
                num -- ;
            }     
        }
        if(l <= r)
        {
            if(!vis[b[l].id])
            {
                vis[b[l].id] = 1 ;
                num ++ ;
            }
        }
    }
    cout << ans << '\n' ;
    return 0 ;
}

G

一、题意

二、题解

三、代码

H

民间题解真好,我也真菜。

这个其实是最可补的一题。

需要深刻理解分治乘。

一、题意

二、题解

三、代码

I

一、题意

二、题解

三、代码

J

一、题意

给一个n*m的0,1矩阵,求满足下列条件的子矩阵个数。

(1)四个边界全是1

(2)不包括边界的部分的0的个数和1的个数的差值的绝对值不超过1

(3)长和宽都大于1

数据范围:1\leqslant n,m \leqslant 500

二、题解

看数据范围考虑O(n^3)

枚举上下边界,然后从左往右扫过去。

上下边界必须都是连续的1,因为内部个数的0,1差值不超过1,所以从左往右扫过去维护一下前缀和就可以在知道右边界时O(1)确定左边界的个数了。

三、代码

#include
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << '*' << x << '\n'
#define ddebug(x , y)  cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair pii ;
typedef pair pll ;
const int mod = 998244353 ;
const int maxn = 500 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
mt19937  rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ; 
int n , m ;
int a[maxn][maxn] ;
int sum[maxn][maxn] ;
int pre1[maxn * maxn * 3] ;
int pre2[maxn * maxn * 3] ;
int offset = 500 * 500 ;
ll ans = 0 ;
int cal(int x1 , int y1 , int x2 , int y2)
{
    if(x1 > x2 || y1 > y2)  return 0 ;
    return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1] ; 
}
void solve(int i , int j , int l , int r)
{
    rep(k , l , r)
    {
        if(cal(i , k , j , k) == j - i + 1)
        {
            int s1 = cal(i + 1 , l , j - 1 , k - 1) ;
            int s2 = cal(i + 1 , l , j - 1 , k) ;
            int temp1 = s1 + offset ;
            int temp2 = s2 + offset ;
            ans += pre2[temp1 - 1] + pre2[temp1] + pre2[temp1 + 1] ;
            pre1[temp1] ++ ;
            pre2[temp2] ++ ;
        }
    }
}
void move(int i , int j , int l , int r)
{
    rep(k , l , r)
    {
        if(cal(i , k , j , k) == j - i + 1)
        {
            int s1 = cal(i + 1 , l , j - 1 , k - 1) ;
            int s2 = cal(i + 1 , l , j - 1 , k) ;
            int temp1 = s1 + offset ;
            int temp2 = s2 + offset ;
            pre1[temp1] = 0 ;
            pre2[temp2] = 0 ;
        }
    }
}
int main()
{
    ios ;
    cin >> n >> m ;
    rep(i , 1 , n)  rep(j , 1 , m)  
    {
        cin >> a[i][j] ;
        if(a[i][j] == 0)  a[i][j] = -1 ;
    }
    rep(i , 1 , n)  rep(j , 1 , m)  sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j] ;
    rep(i , 1 , n)  rep(j , i + 1 , n)
    {
        rep(k , 1 , m)
        {
            if(a[i][k] != 1 || a[j][k] != 1)  continue ;
            int p = k ;
            while(p + 1 <= m && a[i][p + 1] == 1 && a[j][p + 1] == 1)  p ++ ;
            solve(i , j , k , p) ;
            move(i , j , k , p) ;
            k = p ;
        }
    }
    cout << ans << '\n' ;
    return 0 ;
}

K

一、题意

二、题解

三、代码

L

一、题意

二、题解

三、代码

 

你可能感兴趣的:(#,2020牛客多校)