(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4)

这篇具有很好参考价值的文章主要介绍了(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1003 Simple Set Problem

双指针的思想,双端队列

先从小到大排个序

一个一个放到双端队列里,一边放一边维护集合个数为k个

利用滑动窗口,当滑动窗口中集合个数为k时,只需算出滑动窗口最后一个数减去第一个数,然后每次取min就行了

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=1e6+10;
typedef pair<int,int>PII;
typedef long long ll;
int k,c;
int cnt[N];
void solve()
{
    cin>>k;
    int n=0;
    vector<PII>ans;
    for(int i=0;i<k;i++) cnt[i]=0;
    for(int i=0;i<k;i++){
        cin>>c;
        n+=c;
        while(c--){
            int x;
            cin>>x;
            ans.push_back({x,i});
        }
    }
    sort(ans.begin(),ans.end());
    int sum=0;
    int res=2e9;
    deque<int>q;
    for(int i=0;i<n;i++){
        if(!cnt[ans[i].second]) sum++;
        q.push_back(i);
        cnt[ans[i].second]++;
        if(sum<k) continue;
        while(cnt[ans[q.front()].second]>1){
            cnt[ans[q.front()].second]--;
            q.pop_front();
        }
        res=min(res,ans[q.back()].first-ans[q.front()].first);
    }
    cout<<res<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

1006 PSO 

两两组合

期望=所有组合的边数/组合数

组合数为中心节点与其它n-1个节点组合+在其它n-1个节点中选2个的组合(cnt)

所有组合的边数为n-1+2*cnt

当n大于2时,最大值均为2

另外,当n为2时,还需要特判,最大值为1

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
//typedef pair<int,int>PII;
typedef long long ll;
ll n;
ll C2(ll x){
    return x*(x-1)/2;
}
void solve()
{
    cin>>n;
    double res=((double)2*C2(n-1)+n-1)/(C2(n-1)+n-1);
    printf("%.9lf ",res);
    if(n==2) printf("%.9lf\n",1.0);
    else printf("%.9lf\n",2.0);
}
int main()
{
//    ios::sync_with_stdio(false);
//    cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

1010 Kong Ming Qi 

n*m和m*n是等价的,所以统一换成n小m大 

当n为1时,答案明显为(m+1)/2

然后由一个基本图形(图1),可以吃掉连续三个棋子(如图4)

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

所以当n不是1时,我们都可以一直消掉3列

所以我们可以打表在一个范围里,当n和m很大时,都可以通过消掉3列,消掉3行来使得其落在打表范围里

当n等于5并且m等于5时,可以这么消

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

当n大于等于6,并且m大于等于6时,更加可以消3行3列

但是当n为4,m为5时,就只能消掉3列,行就不行了,所以当n和m都大于等于5时,才消3行3列,所以我们打表打到4*4

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
int ans[4][4]=
{
    {1,1,2,2},
    {1,1,2,1},
    {2,2,2,2},
    {2,1,2,1}
};
void solve()
{
    int n,m;
    cin>>n>>m;
    if(n>m) swap(n,m);
    if(n==1){
        cout<<(m+1)/2;
        return;
    }
    while(n>=5) n-=3;
    while(m>=5) m-=3;
    cout<<ans[n-1][m-1]<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

1011 circuit

floyd算法求最小环问题

floyd算法求最短路原理:

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

 得到以下状态转移方程

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

然后可以将最高维k去掉,因为第一维时一层一层算上去的,第k层只需要用到它的上一层,即k-1层,不用前面的其它层,那么只用从1到n的循环,然后一层一层上去就行了,完全可以删掉第一维

于是转化成了d[i][j]=d[i][k]+d[k][j]

对于i->j,最短路径是经过不超过k的中间节点,d[i][j]是由不超过k的中间节点更新的最短距离

所以当枚举到k时,枚举小于k的节点,并判断是否与k相邻,然后再判断是否是环,这样的话这个环上的所有节点都不超过k,这样才能不重不漏

另外,枚举到某个k时,此时更新的最短距离是由小于等于k的中间节点更新的,所以此时去判断a[k][i]+dist[i][k]<mn(i从1到k-1)用到的dist[i][k]才会准确

关于为什么不能重新在外面写一个k从1到n的循环,将判断环的部分放在这个循环里:

首先我们不重不漏地枚举两个点,方法是对于编号为k的节点,我们只枚举编号比它小的节点(即1到k-1),然后如果两个点相邻,即k->i有一条边,那么我们就看k->i的权值加上i到k的最短距离是不是正无穷,如果不是,那么说明有环

但是我们枚举环的时候也得做到不重不漏,如下图所示:

当k为3时,我们会找到比它小的编号1,发现3->1有一条边,然后我们会算3->1的边权值加上1到3的最短距离是不是正无穷,发现不是,那么就是一个环,但是呢,我们只能找由2更新1到3的最短距离的这个环,不能找由4更新1到3的最短距离的这个环,不然的话,当我们枚举到k为4时,又会找到4->3这条边,会再次找到4->3->1这个环,那么同样的环就找到了两次

所以我们只能找由编号小于等于k的节点更新的最短距离,而这刚好和floyd算法相符,当枚举到k时,更新的最短距离都是由小于等于k的中间节点更新的,所以每枚举一次k,我们就找一次环

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4),2023杭电多校,算法,c++

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=510,mod=998244353;
const ll INF=1e18;
int a[N][N];//a[i][j]表示i和j边权值
ll dist[N][N];//dist[i][j]表示i和j之间的最短距离
int cnt[N][N];//cnt[i][j]表示i和j之间的最短路的数量
int n,m;
void solve() {
    cin>>n>>m;
    //将自环距离初始化为0,其它初始化为INF
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            a[i][j]=0,dist[i][j]=INF;
        }
    }
    for(int i=1; i<=n; i++) dist[i][i]=0;

    for(int i=0; i<m; i++) {
        int x,y,z;
        cin>>x>>y>>z;
        a[x][y]=z;
        dist[x][y]=z;
        cnt[x][y]=1;
    }
    ll mn=INF;
    ll count=0;
    for(int k=1; k<=n; k++) {
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                if(dist[i][j]>dist[i][k]+dist[k][j]) {
                    dist[i][j]=dist[i][k]+dist[k][j];
                    cnt[i][j]=1ll*cnt[i][k]*cnt[k][j]%mod;
                } else if(dist[i][j]==dist[i][k]+dist[k][j]) {
                    cnt[i][j]=(cnt[i][j]+1ll*cnt[i][k]*cnt[k][j])%mod;
                }
            }
        }
        for(int i=1; i<=k-1; i++) {
            if(a[k][i]) {
                if(a[k][i]+dist[i][k]<mn) {
                    mn=a[k][i]+dist[i][k];
                    count=cnt[i][k];
                } else if(a[k][i]+dist[i][k]==mn) {
                    count=(count+cnt[i][k])%mod;
                }
            }
        }
    }
    if(mn==INF) mn=-1,count=-1;
    cout<<mn<<" "<<count<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

1012 a-b Problem

对于每一个ai,bi,求它们的和,然后从大到小排序,依次取

原因在于自己取了其中一个,对方没有取另一个,那么自己比对方就多了两者之和

AC代码:文章来源地址https://www.toymoban.com/news/detail-618418.html

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define endl '\n'
//#define int long long
using namespace std;
const int N=1e5+10;
//typedef pair<int,int>PII;
typedef long long ll;
ll n;
struct node{
    ll a;
    ll b;
    ll sum;
    bool operator<(const node &W)const{
        return sum>W.sum;
    }
}ans[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>ans[i].a>>ans[i].b;
        ans[i].sum=ans[i].a+ans[i].b;
    }
    sort(ans+1,ans+1+n);
    ll sum1=0,sum2=0;
    for(int i=1;i<=n;i++){
        if(i%2==1) sum1+=ans[i].a;
        else sum2+=ans[i].b;
    }
    cout<<sum1-sum2<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    solve();
    return 0;
}

到了这里,关于(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023“钉耙编程”中国大学生算法设计超级联赛(5)

    给你台风的轨迹坐标以及避难所的坐标,台风的半径不可预测,求让每个避难所不安全的最小台风半径是多少。 枚举每个点到所有“线段”的距离取个min。 附上队友的代码(懒): 给定一个长度为n的字符串,编号1-n,求满足条件的区间(i, j)的数量: ①1 ≤ i < j ≤ n ②

    2024年02月09日
    浏览(46)
  • 2023“钉耙编程”中国大学生算法设计超级联赛(1)Hide-And-Seek Game

    2023“钉耙编程”中国大学生算法设计超级联赛(1)Hide-And-Seek Game 题目大意 有一棵有 n n n 个节点的树,小 S S S 和小 R R R 在树上各有一条链。小 S S S 的链的起点为 S a S_a S a ​ ,终点为 T a T_a T a ​ ;小 R R R 的链起点为 S b S_b S b ​ ,终点为 T b T_b T b ​ 。 小 S S S 和小 R R

    2024年02月16日
    浏览(47)
  • 【树链+EXGCD】杭电多校第一场 A

    1001 Hide-And-Seek Game (hdu.edu.cn) 题意: 给定一棵树和两条路径,每条路径都有起点和终点,起始时起点有人,每隔一秒都会往终点走一步,会从起点走向终点再会起点这样不断地周期性地走,让你求一点,使得两个人能在这点相遇且花的时间最少   思路: 首先答案一定是两条路

    2024年02月16日
    浏览(45)
  • 2022杭电多校第一场B题Dragon slayer

    题目链接Problem - 7139 (hdu.edu.cn) 数据范围为15,直接枚举所有墙的方案,然后看是否能搜索到终点,如果可以就更新ans 需要注意的是如何处理:起点终点坐标+0.5造成的下标为小数,这里把所有坐标都乘2来避免double类型的出现 代码如下:

    2024年02月16日
    浏览(41)
  • 题解 | #1005.List Reshape# 2023杭电暑期多校9

    签到题 按一定格式给定一个纯数字一维数组,按给定格式输出成二维数组。 读入初始数组字符串,将每个数字分离,按要求输出即可 参考代码为已AC代码主干,其中部分功能需读者自行实现

    2024年02月12日
    浏览(40)
  • 2023年天府杯全国大学生数学建模竞赛B题中国环境问题的治理解题全过程

       问题背景:    随着经济的快速发展和人口的持续增长,中国的环境问题已经成为了一个急需解决的重要问题。这些环境问题不仅对人们的健康和生活质量产生了巨大的影响,还对生态系统和生态平衡造成了极大的破坏。近年来,中国政府积极推动环保事业的发展,通

    2024年02月08日
    浏览(47)
  • 2023年度第四届全国大学生算法设计与编程挑战赛(春季赛)

     A 题目描述        有一个长为 n (1le n le 1000)n (1≤n≤1000) 的序列,序列上的元素两两不同。你需要用最少的操作步数翻转这个序列。        每次操作你需要给出三个数 i,j,k(1le ile j k le n)i,j,k(1≤i≤jk≤n),交换序列中下标属于 [i,j][i,j] 的元素与下标属于 [j+1,k][j+

    2024年02月08日
    浏览(128)
  • 2023年第十五届“中国电机工程学会杯”全国大学生电工数学建模竞赛题目 A题:电采暖负荷参与电力系统功率调节的技术经济分析

    建设以新能源为主体的新型电力系统是应对全球气候变化挑战的重要举措。高比例新能源接入导致电力系统调节能力稀缺,亟需开发新的调节资源,如火电深度调峰、建设抽水蓄能电站、配置储能和挖掘负荷中的调节能力等。现代电力负荷中含有较大比重的温控型负荷(如空

    2024年02月06日
    浏览(47)
  • 23.7.25 杭电暑期多校3部分题解

    题目大意 你有一个长度为 n n n 的序列,你每次可以向一个栈内放一个数,如果栈不为空并且栈顶的数大于你放的数,那么你放的数会变成栈顶的数再放入,问当栈的大小为 1 1 1 到 n n n 时分别有几种情况 解题思路 考虑dp, f i , j f_{i,j} f i , j ​ 表示放了 i i i 个数,最大的数

    2024年02月15日
    浏览(36)
  • 23.8.8 杭电暑期多校7部分题解

    题目大意 有两个玩家和一棵树,初始状态玩家一和玩家二分别在两个点 x ,   y x,space y x ,   y ,每次操作可以走一个与当前点有连边并且双方都没走到过的点,问最后是谁赢 解题思路 因为不能走走过的点,因此每个人走的路径一定是一条链 很明显当玩家一不选择往与玩家二

    2024年02月13日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包