IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2021 ICPC 江西省大学生程序设计竞赛【ABJHKL】 -> 正文阅读

[数据结构与算法]2021 ICPC 江西省大学生程序设计竞赛【ABJHKL】

先补这么多吧。

目录

比赛链接

A Mio visits ACGN Exhibition

B?Continued Fraction

J?LRU

H?Hearthstone So Easy

K?Many Littles Make a Mickle

L It Rains Again


比赛链接

牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

A Mio visits ACGN Exhibition

题意:

有n * m个格子,每个格子都有一个数字:0 或 1 。现在我们要从(1,1)走到(n,m),只能往右或者往下走,问存在多少种路线使得至少经过p个0和q个1

思路:

? ? ? ? 这题应该还是比较简单的动态规划,就是有两个地方需要优化,我没有想到
????????这题主要还是内存限制,数据范围是1 <= n, m <= 500,0 <= p, q <=10000。而我们需要记录他的位置信息以及经过了多少个0和1。因为已知每次经过的总数等于i + j - 1,所以这里只需要记录经过了多少个0或者经过了多少个1就可以了,但也至少需要三维才可以实现,空间复杂度在1e9。

????????我用f[ i ][ j ][ k ]来表示当走到第 i 行第 j 列,经过 k 个 1?时的方案总数

????????第一个优化:虽然这里p和q的范围给到了10000,但因为每次只能往右或者往左走,所以其实p和q最多只能是1000(这也要欺骗我呜)。但这样复杂度仍然是1e8
? ? ? ? 第二个优化:因为最多只可能走到下一行或者当前行,所以当前状态只与这一行和上一行有关,所以可以用滚动数组优化。那dp数组第一维的大小就可以优化到2。现在复杂度只有1e6啦

? ? ? ? ∵? 0 ^ 1 = 1;1 ^ 0 = 0
? ? ? ? ∴ 可以用异或来进行这二维的转换

? ? ? ? 用s表示当前的行状态,那s ^ 1就表示上一行的状态,s ^= 1就表示走到了下一行。

#include<iostream>
using namespace std;
const int N = 510;
const int M = 1010;
const int mod = 998244353;
int f[2][N][M];//记录当坐标在(i,j)的时候,经过数字为1的次数是k次
int g[N][N];
int main()
{
    int n, m, p, q;
    cin >> n >> m >> p >> q;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= m; ++ j)
            cin >> g[i][j];
    int s = 0;
    if(g[1][1]) f[s][1][1] = 1;
    else f[s][1][0] = 1;
    for(int i = 1; i <= n; ++ i)
    {
        for(int j = 1 ; j <= m; ++ j)
        {
            if(i == 1 && j == 1)
                continue;
            for(int k = 0; k <= i + j - 1; ++ k)
            {
                if(g[i][j])
                    f[s][j][k] = (f[s^1][j][k-1] + f[s][j-1][k-1])%mod;
                else
                    f[s][j][k] = (f[s^1][j][k] + f[s][j-1][k])%mod;
            }
        }
        s ^= 1;
    }
    s ^= 1;
    long long ans = 0;
    for(int k = q; k <= n + m - 1; ++ k)
    {
        if(n + m - 1 - k >= p)
            ans = ( ans + f[s][m][k] )%mod;
    }
    cout << ans << endl;
}

B?Continued Fraction

每次保存x/y,之后交换分子分母。

#include<iostream>
#include<cstring>
using namespace std;
const int N = 110;
int a[N];
int main()
{
    int t;
    cin >> t;
    while( t -- )
    {
        int k = 0;
        int x, y;
        cin >> x >> y;
        while(y)
        {
            int t = x / y;
            a[++k] = t;
            x %= y;
            swap(x, y);
        }
        cout << k - 1 << ' ';
        for(int i = 1; i <= k  ; ++ i)
            cout << a[i] << ' ';
        cout << endl;
    }
    
}

J?LRU

参考题解:?2021 ICPC 江西省大学生程序设计竞赛 J.LRU 二分_HeartFireY的博客-CSDN博客

题意:

????????感觉这题比较难看懂吧我看了好久 但是看懂了之后题意还是很简单的。
????????就是有一个缓存块,里面的容量只有有限个,现在给了n个数字,n个数字一个个放进缓存块里。
????????如果缓存块里已有相同的数字,就会发生缓存命中,进行替换;
????????如果缓存块里没有相同的数字且缓存块容量满了,新的数字就和放入时间最早的缓存块进行替换;
????????如果缓存块里没有相同的数字且缓存块没有满,直接放进去就行了。
????????另给了一个数字k,问容量最小为多少,可以发生至少k次的缓存命中。

思路:

????????显然是要二分。
????????因为放进去的时间先后,其实就是a[i]的编号先后,我们可以用一个set来维护编号先后,map来快速寻找数字对应的下标及缓存块里有没有这个数字。那如果要替换的话,最早进入的其实就是set的第一个,替换后也把对应的map更新就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int > PII;
int n, k;
const int N = 1e5 + 10;
int a[N];
bool check(int x)
{
    set<PII>st;//放缓存中的数字
    map<int, int>mp;//帮助找到每个元素最后一次出现的位置
    int cnt = 0;
    for(int i = 1; i <= n; ++ i)
    {
        if(mp.count(a[i]))//如果缓存里已经有这个数字了 就更新一下坐标
        {
            ++ cnt ;//次数++
            //删除a[i]元素最后一次出现的位置
            st.erase(make_pair(mp[a[i]],a[i]));
            mp[a[i]] = i;
            st.insert(make_pair(i,a[i]));
            continue;
        }
        else if(st.size() == x)//如果缓存已经满了 且缓存里没有该数字 就要删除最早出现的元素然后插入新元素
        {
            PII t = *st.begin();
            st.erase(st.begin());
            mp.erase(t.second);
            mp[a[i]] = i;
            st.insert(make_pair(i,a[i]));
            continue;
        }
        else//如果缓存没有满 且没有相同数字 直接插入就可以了
        {
            mp[a[i]] = i;
            st.insert(make_pair(i,a[i]));
        }
    }
    return cnt >= k;
}
int main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; ++ i)
        cin >> a[i];
    int l = 1, r = n, ans = -1;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(check(mid))
            r = mid , ans = r;
        else
            l = mid + 1;
    }
    if(ans < 0)
        puts("cbddl");
    else
        cout << ans << endl;
}

H?Hearthstone So Easy

题意:

????????是轮到每个人的回合时都要经历draw cards,play cards两个过程。如果自己没有牌然后draw cards的话就会消耗一定的体力,play cards可以让对方减k点血量,也可以让自己恢复k点血量。

思路:

????????一道博弈论的题吧 不知道为什么看榜单好像没有很多人写出来 但是感觉还是比较容易想到的。

????????其实不知道为什么这里说如果玩家牌组没牌的话,抽牌时会将疲劳值增加一倍,然后生命值减去疲劳值。因为其实玩家一直在抽牌和玩牌吧,手里应该是一直没有牌的。

????????因为k值以及玩家生命值都是固定且相同的,所以如果慢慢耗下去的话,先手肯定会先死。

????????如果先手选择恢复生命值的话,后手肯定选择攻击,这样往复下来,只是玩家对疲劳值的消耗,对先手是不利的,所以先手不会选择恢复。

????????由此可知,先手是会一直选择攻击的,而后手一定是会一直选择恢复的,除非到最后轮到后手的时候,先手体力不支,只需要攻击一次先手就“死”了。但这样其实也是对疲劳值的消耗,因为先手攻击多少,后手就可以恢复多少,而先手的体力是先消耗的。

????????这样可以推断,如果先手第一次不能把后手攻击死的话,先手必败。

#include<iostream>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t -- )
    {
        int n, k;
        cin >> n >> k;
        if(n == 1)
            puts("freesin");
        else
        {
            if(n-k > 1)
                puts("freesin");
            else
                puts("pllj");
        }
    }
}

K?Many Littles Make a Mickle

说签到题就是真签到题

#include<iostream>
using namespace std;
int main()
{
    
    int t;
    cin >> t;
    while(t --)
    {
        int n, m;
        cin >> n >> m;
        long long ans = 0;
        for(int i = 1; i <= n; ++ i)
            ans += i*i*m;
        cout << ans <<endl;
    }
}

L It Rains Again

差分

但是这题又有两个小小的不一样

1.赛时差点就写出来了?但是一直写的num[x2+1] --。但是这题因为是算的是单位长度而不是有多少个数字,所以应该是num[x2]--。就比如区间[1,2],其实只挡了1个单位长度的雨

2.这题不是求区间和,所以不管区间覆盖多少次,只要覆盖了,就只算一个单位长度。所以下面遍历的时候,只要num[i]>0,ans就只加一

#include<iostream>
#include<cstring>
using namespace std;
const int N = 100010;
bool st[N];
int num[N];
int main()
{
    int n;
    cin >> n;
    int ans = 0;
    while(n --)
    {
        int x1,x2,y1,y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if(x2 < x1) swap(x1, x2);
        num[x1] ++;
        num[x2] --;
    }
    for(int i = 1; i <= 100000; ++ i)
    {
        num[i] += num[i-1];
        if(num[i] > 0) ans++ ;
    }
    cout << ans <<endl;
    
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:44:27  更:2022-05-05 11:49:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:21:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码