2023CCPC广东省赛

2023广东省赛

Dashboard - The 2023 Guangdong Provincial Collegiate Programming Contest - Codeforces

A 枚举
C 循环
K ⭐⭐ 搜索
I ⭐⭐ 二分
D ⭐⭐ 贪心
M ⭐⭐ 几何
B ⭐⭐⭐ 单调队列优化DP
E ⭐⭐⭐ 字符串 思维
F<---- ⭐⭐⭐ 线段树 二分
J ⭐⭐⭐⭐ 数学
H ⭐⭐⭐⭐ 建图
G ⭐⭐⭐⭐ 思维
L ⭐⭐⭐⭐ 图论

A - Programming Contest(签到)

#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 1e5 + 10 , INF = 2e9;

int n,m;
int ans;
int a[N];

void solve()
{
    cin>>n;
    int k;
    cin>>k;
    for(int i=0;i<k;i++)
        cin>>a[i];

    cin>>m;

    int cnt=0;
    for(int i=0;i<k;i++)
        if(a[i]>=n&&a[i]<=m)
            cnt++;

    cout<<m-n+1-cnt<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","r",stdin);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;
    cin>>T;
    while(T--)
    {
        solve();
    }

    return 0;
}

C - Trading(模拟)

#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

struct Node
{
    int w;
    int num;
}q[N];
int n;

bool cmp(Node a,Node b)
{
    if(a.w==b.w) return a.num<b.num;
    return a.w<b.w;
}

void solve()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>q[i].w>>q[i].num;
    }

    sort(q,q+n,cmp);

    int ans=0;
    int l=0,r=n-1;
    while(l<r)
    {
        // cout<<l<<' '<<r<<endl;
        if(q[r].num>=q[l].num)
        {
            ans+=(q[r].w-q[l].w)*q[l].num;
            q[r].num-=q[l].num;
            l++;
        }
        else
        {
            ans+=(q[r].w-q[l].w)*q[r].num;
            q[l].num-=q[r].num;
            r--;
        }
    }
    cout<<ans<<endl;


}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","r",stdin);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

K - Peg Solitaire(搜索)

思路:

直接dfs 遇到棋子判断能够向四个方向跳跃 保存最小的值作为答案
棋盘状态需要回溯

/*
K - Peg Solitaire


 */

#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;

typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,m,k;
int g[10][10];
int ans;

void dfs(int now)
{
    ans=min(ans,now);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(g[i][j])
            {
                //向上跳
                if(i>=3)
                {
                    if(g[i-1][j]&&!g[i-2][j])
                    {
                        g[i][j]=g[i-1][j]=0;
                        g[i-2][j]=1;
                        dfs(now-1);
                        g[i][j]=g[i-1][j]=1;
                        g[i-2][j]=0;
                    }
                }
                //向下跳
                if(i<=n-2)
                {
                    if(g[i+1][j]&&!g[i+2][j])
                    {
                        g[i][j]=g[i+1][j]=0;
                        g[i+2][j]=1;
                        dfs(now-1);
                        g[i][j]=g[i+1][j]=1;
                        g[i+2][j]=0;
                    }
                }
                if(j>=3)
                {
                    if(g[i][j-1]&&!g[i][j-2])
                    {
                        g[i][j]=g[i][j-1]=0;
                        g[i][j-2]=1;
                        dfs(now-1);
                        g[i][j]=g[i][j-1]=1;
                        g[i][j-2]=0;
                    }
                }
                if(j<=m-2)
                {
                    if(g[i][j+1]&&!g[i][j+2])
                    {
                        g[i][j]=g[i][j+1]=0;
                        g[i][j+2]=1;
                        dfs(now-1);
                        g[i][j]=g[i][j+1]=1;
                        g[i][j+2]=0;
                    }
                }
            }
        }
    }
}

void solve()
{
    memset(g,0,sizeof g);
    cin>>n>>m>>k;
    for(int i=0;i<k;i++)
    {
        int a,b;
        cin>>a>>b;
        g[a][b]=1;
    }

    ans=k;
    dfs(k);

    cout<<ans<<endl;

}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","r",stdin);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

I - Path Planning(二分)

思路:

如果答案为x那么路径的序列一定存在0,1,2...x-1 具有二分性,考虑二分答案

因为路径中一定存在0,1,2,...x-1所以检查这些数的坐标 看能不能走到n,m

另一个思路:逐行逐列扫描 如果该数<x也就是说该位置必须走到 因为是按顺序扫描的且只能走右边和下边
所以后面要走的位置的列数一定大于等于当前最后一列 如果不行说明该路径不存在

/*
I - Path Planning

 */

#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 1e6 + 10 , INF = 2e9;

int n,m;
int g[N];

bool check(int x)
{
    int last=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if(g[i*m+j]<x)
            {
                if(last>j)
                    return false;
                last=j;
            }
        }
    return true;
}

void solve()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>g[i*m+j];

    int l=0,r=n*m;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    cout<<r<<endl;
}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","r",stdin);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}

D - New Houses(贪心)

思路:

最终一定有k个人有邻居 n-k个没有邻居

k的范围是[2,n]

也就是说挑k个ai并且n-k个bi
如果第i个人对答案的贡献是bi,而他挑ai使答案更优的情况一定使ai>bi
所以k个人如何挑选 ai-bi 从大到小排序 选前k个大的人
同时 k个人有邻居而n-k个没有邻居需要的房子数至少是k+2(n-k)=2n-k;

所以答案在k=2,3,...n中取最大值就可以

注意如果我们一开始求出所有bi的和然后每次取ai则可以O(1)求解出每次的答案

/*
D - New Houses


 */

#include <bits/stdc++.h>
#define bug cout << "***************" << endl
#define look(x) cout << #x << " -> " << x << endl
#define endl '\n'
#define int long long
#define YES cout << "YES" << endl;
#define NO cout << "NO" << endl;

using namespace std;
typedef pair<int, int> PII;

constexpr int N = 2e5 + 10 , INF = 2e9;

int n,m;
int a[N],b[N];


void solve()
{
    cin>>n>>m;

    vector<int> vi;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        vi.push_back(a[i]-b[i]);
        sum+=b[i];
    }

    sort(vi.begin(),vi.end());

    int ans=0;
    if(m>=2*n-1) ans=sum;

    sum+=vi[n-1];
    for(int k=2;k<=n;k++)
    {
        sum+=vi[n-k];
        if(m>=2*n-k) ans=max(ans,sum);
    }

    cout<<ans<<endl;

}


signed main()
{
    //freopen("check.in","r",stdin);
    //freopen("check.out","r",stdin);
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T;
    //T=1;
    cin>>T;
    while(T--)
    {
      solve();
    }



    return 0;
}
posted @ 2024-04-23 23:54  Danc1ng  阅读(105)  评论(0)    收藏  举报