Codeforces Round 997 (Div. 2) A~C

今天的封面是水母猫猫和佩佩,原图在这里,记得关注画师夏狩大大
至此,天鹅完成了连续四场比赛在四个不同比赛上四次分的壮举!(ABC388,CodeChef169,牛客月赛109,CF997)
这场难度很有问题啊,D题断层太大了吧,不过还好我前面写得快,真就手速场

A - Shape Perimeter

题意

有一张大小为 m × m m\times m m×m的印章,然后一开始在 ( 0 , 0 ) (0,0) (0,0)的位置(但是没盖下去),然后进行了 n n n次移动,每次两个方向移动的距离告诉你,让你求最后盖出来的这个图案的总周长。

思路

注意到数据范围里面说了 x i x_i xi y i y_i yi ( 1 ≤ x i , y i ≤ m − 1 1 \le x_i, y_i \le m - 1 1xi,yim1) ,也就是每次移动的范围不大于边长,所以最后的图形一定是连起来的,用我们小学二年级就学过的求楼梯型周长可以知道只需要平移边转化为长方形就可以了

补型法

如图,算蓝线周长即可

代码

//
// Created by Swan416 on 2025-01-17 22:29.
//
#include <bits/stdc++.h>
#define maxOf(a) *max_element(a.begin(),a.end())
#define minOf(a) *min_element(a.begin(),a.end())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int dx,dy;
    int x,y;
    scanf("%d%d",&dx,&dy);
    x=dx,y=dy;
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        x+=a;
        y+=b;
    }
    x+=m;
    y+=m;
    int ans=(x-dx+y-dy)*2;
    printf("%d\n",ans);
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

B - Find the Permutation

题意

构造一个排列 p p p,使得按照以下操作依据这个排列得出的图是给定的无向图:

  • 对于每一组整数 1 ≤ i < j ≤ n 1 \le i < j \le n 1i<jn 当且仅当 p i < p j p_i < p_j pi<pj 时给 p i p_i pi p j p_j pj 连一条边。

思路

如果你是参加了学校寒假集训的新生,那这道题可以让你直观感受到实际XCPC题目和所谓板子题的区别在哪里,我们集训的第一天就写过这样一道题 HDU - 1285 确定比赛名次 ,这题就是典型的板子题,因为题目基本上算是明确告诉你这题需要使用拓补排序这样一个算法

但是这题同样其实也算是拓补排序板子吧也是拓补排序,条件给的要隐晦很多,我们想, i < j i<j i<j 是不是就是一个先后顺序关系,然后前者小于后者才会建一条边,那这个边其实就是上面那题里面拓补排序的条件嘛,想通这一点我们直接敲一个拓补排序就行了

代码

//
// Created by Swan416 on 2025-01-17 22:45.
//
#include <bits/stdc++.h>
#define maxOf(a) *max_element(a.begin(),a.end())
#define minOf(a) *min_element(a.begin(),a.end())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int n;
    scanf("%d",&n);
    vector<string> G(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>G[i];
        G[i]="#"+G[i];
    }
    vector<pii> edge;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(G[i][j]=='1')
            {
                edge.emplace_back(i,j);
            }
            else
            {
                edge.emplace_back(j,i);
            }
        }
    }
    // 拓补排序
    vector<int> in(n+1,0);
    for(auto [u,v]:edge)
    {
        in[v]++;
    }
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
        {
            q.push(i);
        }
    }
    vector<int> ans;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        ans.push_back(u);
        for(auto [v,w]:edge)
        {
            if(v==u)
            {
                in[w]--;
                if(in[w]==0)
                {
                    q.push(w);
                }
            }
        }
    }
    if(ans.size()!=n)
    {
        printf("-1\n");
        return;
    }
    for(auto x:ans)
    {
        printf("%d ",x);
    }
    printf("\n");
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

C - Palindromic Subsequences

题意

构造一个数组,使得其中的最长回文子串的个数大于 n n n

思路

看样例1,直接就已经把构造方法给你了,我们两个1把其他数夹在中间,然后最右边再补一个2贡献几个答案就出来了

代码

//
// Created by Swan416 on 2025-01-17 22:53.
//
#include <bits/stdc++.h>
#define maxOf(a) *max_element(a.begin(),a.end())
#define minOf(a) *min_element(a.begin(),a.end())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
// 6 -> 1 1 2 3 1 2
// 7 -> 1 1 2 3 4 1 2
// 8 -> 1 1 2 3 4 5 1 2
// 9 -> 1 1 2 3 4 5 6 1 2
// 10 -> 1 1 2 3 4 5 6 7 1 2
// 11 -> 1 1 2 3 4 5 6 7 8 1 2

void solve()
{
    int n;
    scanf("%d",&n);
    printf("1 ");
    for(int i=1;i<=n-3;i++)
    {
        printf("%d ",i);
    }
    printf("1 2\n");
}

int main()
{
    int T=1;
    scanf("%d",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值