Codeforces Round 965 (Div. 2)

传送门:https://codeforces.com/contest/1998

目录

A. Find K Distinct Points with Fixed Center

B. Minimize Equal Sum Subarrays

C. Perform Operations to Maximize Score

D. Determine Winning Islands in Race

A. Find K Distinct Points with Fixed Center

题意:

 反思:赛时没考虑到不同的组必须不同(赛时AC,但赛后被hack)

错解:

void solve()
{
    int x , y , k;
    cin >> x >> y >> k;
    int sum1 = 0 , sum2 = 0;
    for(int i = 1 ; i <= k - 1; i++)
    {
        sum1 += i; sum2 += i;
        cout << i << " " << i << endl;
    }
    cout << k * x - sum1 << " " << k * y - sum2 << endl;
    // 最后的解可能与之前的解相等
}

思路:(构造题)

对称的思想

1. 当 k 为偶数时 ( x - 1 , y - 1 )  , ( x +  1 , y + 1 ) ......

2. 当k为奇数时 ( x - 1 , y - 1 ) , ( x + 1 , y + 1 ) ..... ( x , y )

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
void solve()
{
    int x , y , k;
    cin >> x >> y >> k;
    for( int i = 1 ; i <= k / 2; i++)
    {
        cout << x - i << " " << y - i << endl;
        cout << x + i << " " << y + i << endl;
    }
    if( k & 1 )cout << x << " " << y << endl;
}
signed main()
{
    int tt = 1;
    cin >> tt;
    while(tt--)solve();
    return 0;
}

B. Minimize Equal Sum Subarrays

题意:

思路:构造题

1. 当 x < n 时 , x++

2. 当  x == n 时,x = 1

配对数始终为1

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int a[N];
int sum[N];
void solve()
{
   int n;
   cin >> n;
   for( int i= 1; i<= n ; i++)
   {
        int x ; cin >> x;
        if( x == n )cout << 1 << endl;
        else cout << x + 1 << endl;
   }
   cout << endl;
}
signed main()
{
    int tt = 1;
    cin >> tt;
    while(tt--)solve();
    return 0;
}

C. Perform Operations to Maximize Score

题意:

给定 有 n 个元素的数组 a , b 和整数 k , 最多可以执行 k 次操作(操作为选择索引 i , 当b[i] == 1 时,可以将对应的a[i]++ , 求 max + median 的最大值)

思路:

1 . 一直加到某个数上,从而改变最大值 

2. 分开加到某个数上 , 此时有两种情况

最大值改变 或 中位数改变 ,这种情况的最优解 <= 1 

中位数改变,二分答案最大中位数

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 2e5 + 10;
typedef pair<int, int> pii;
pii a[N]; int n, k;
bool check(int x)
{
    int cnt = 0;
    vector<int> b;
    for (int i = 1; i <= n - 1; i++)
    {
        if (a[i].first >= x)cnt++;
        else if( a[i].second == 1 ) b.push_back(x - a[i].first);
    }
    reverse(b.begin(), b.end());
    x = k;
    for (auto e : b)
    {
        if (x >= e) {
            cnt++;
            x -= e;
        }
    }
    return cnt >= ( n + 1 ) / 2 ;
}
void solve()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i].first;
    for (int i = 1; i <= n; i++) cin >> a[i].second;
    sort(a + 1, a + n + 1);
    int ans = 0;
    // 改变最大值 ,一直加到某个数上
    for (int i = 1; i <= n; i++)
    {
        if (a[i].second == 1)
        {
            int mc = 0;
            if (i <= n / 2)mc = a[n / 2 + 1].first;
            else mc = a[n / 2].first;
            ans = max(ans, a[i].first + mc + k);
        }
    }
    int left = 0;
    int right = 1e9;
    // 枚举中位数
    while (right > left)
    {
        int mid = left + right + 1 >> 1;
        if (check(mid)) left = mid;
        else right = mid - 1;
    }
    ans = max(ans, a[n].first + left);
    cout << ans << endl;
}
signed main()
{
    int tt;
    cin >> tt;
    while (tt--)solve();
    return 0;
}

D. Determine Winning Islands in Race

题意:

有 A , B 两人,A可以走主桥和备用桥 , B只能走备用桥,给定 n 个岛屿和 m 条备用桥,到达第n个岛屿获胜,当一个人离开岛屿后,这座岛屿和连接的所有桥都将倒塌,若 B 可以从 i ( 1 <= i <= n - 1 )岛屿先出发,如果从 i 岛屿出发能够获胜,则输出1 ,否则输出0

思路:

若要 B 输 ,则到达某个岛屿之前 A 先到达 ,因为 A 只能从 1 号岛屿出发,若要抢先到达,肯定需要走备用桥,假设备用桥 沟通 i , j   A 的出生地为 loc

则有 loc >= i + 1 && j - loc > t[i] + 1

可以求出 loc 的范围 [ i + 1 ,  j - t[i] - 2 ] , 也就是 当 loc 属于此范围必输

则可以枚举每一个备用桥,求出 loc 的范围

设 loc 并起来的总范围是  K 

A 能够获胜的区间是 [ 1 , n - 1] - K

我们在维护总范围时,可以使用差分 让ans[ i + 1]++ , ans[ j - t[i] - 1]--

[ i + 1 , j - t[i] -2 ] 的前缀和 > 0不符合题意 , 此区间外前缀和 均等于 0

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
int h[N] , e[N] , ne[N] , idx;
int dist[N];
void add( int a , int  b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void solve()
{
    int n , m;
    cin >> n >> m;
    for( int i = 1 ;i <= n ;i++)h[i] = -1;
    for( int i= 1; i<= n;i++)dist[i] = 0x3f3f3f3f;
    idx = 0;
    for( int i = 1 ;i < n; i++)add( i , i + 1 );
    for( int i = 0 ;i < m; i++)
    {
        int a, b;
        cin>> a>>b;
        add( a , b );
    }
   
    queue<int> que;
    que.push(1);
    dist[1] = 0;
    while(que.size())
    {
        auto t = que.front();
        que.pop();
        for( int i = h[t] ; i != -1 ; i = ne[i] )
        {
            int j = e[i];
            if( dist[j] > dist[t] + 1 )
            {
                dist[j] = dist[t] + 1;
                que.push(j);
            }
        }
    }
    vector<int> ans( n + 1 , 0 );
    for( int i = 1; i < n; i++)
    {
        for( int j = h[i] ; j != -1 ; j = ne[j] )
        {
            int k = e[j];
            if( i + 1 <= k - dist[i] - 2 ){
                ans[i+1]++;
                ans[k-dist[i]-1]--;
            }
        }
    }
    for( int i = 1 , sum = 0 ; i < n ;i++)
    {
        sum += ans[i];
        if( sum == 0 )cout << 1;
        else cout << 0;
    }
    cout << endl;
    
    
    idx = 0;
}
int main()
{
    int _;
    cin >> _;
    while(_--)solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值