0
点赞
收藏
分享

微信扫一扫

大连大学2022 4月程序设计竞赛

天涯学馆 2022-04-17 阅读 113
算法

E 数圆圈(规律 模拟)

Description:

​ 定义f(x) = x里各位圆圈数量之和

​ 现在给定x 对x进行k次f(x)操作 返回结果

​ 0, 6, 9 = 1; 8 = 2;

Solution:

​ 那我们考虑最坏的情况 那就是17位上面都是8 那也是17*2 会化成一个很小的数

​ 我们就可以知道 对于一个x 我们可以通过数十次次迭代之内 将他变成01的循环态

​ 于是我们模拟即可 (用字符串不会挂 但是用整数是会挂的 因为x可能是负数

Code:

LL get(LL x)
{
    LL res = 0;
    string s = to_string(x);
    for(int i = 0; i < s.size(); i++)
    {
        if(s[i] == '8')    res += 2;
        if(s[i] == '0' || s[i] == '6' || s[i] == '9')    res ++;
    }
    return res;
}

void solve()
{
    LL x, k;
    cin >> x >> k;
    LL res = x;
    while(k)
    {
        res = get(res);
        k --;
        if(res == 0 || res == 1)    break;
    }
    
    if(res == 1 && k)
    {
        if(k & 1)    res = 0;
        else res = 1;
    }
    else if(res == 0 && k)
    {
        if(k & 1)    res = 1;
        else res = 0;
    }
    
    cout << res << endl;
}

F 旅行(图论)

Description:

​ 给出一个图 然后询问一下点a在不在1到n的最短路径上

Solution:

​ 方法1:用佛洛依德跑一遍 判断g[1] [a] + g[a] [n] ?= g[1] [n]

​ 方法2:首先用迪杰斯特拉从1跑到n 得到从1为起点到各个点的最短路

​ 然后再建反边 从n开始跑到1 得到以n为起点到各个点的最短路

Code:

代码就先不写了 以后试图补一补

H 寻找最大差值(思维)

Description:

​ 给定数组a 求a_j - a_i (且a_j > a_i) 的最大值 要求i < j 如果这个数不存在就输出-1

Solution:

​ 一开始就各种二分 排序 各种想 就是想不到怎么写 那其实可以用On写过

​ 我们倒序循环j来维护一个mx=max(a[j]) 然后用mx去减去比他更小的a[i] 这时候必定存在i < j

Code:

int a[100010];
void solve()
{
    int n;
    cin >> n;
    rep(i, 1, n + 1)
        cin >> a[i];
    
    int mx = 0;
    int res = -1;
    per(i, n, 1)
    {
        mx = max(mx, a[i]);
        if(mx - a[i] > 0)   res = max(mx - a[i], res);
    }        
    cout << res << '\n';
}

H Raksasa的轻功(读题)

Description:

​ 给定数组a 可以从任一点开始找最长连续下降序列(可以向左或者向右)

Solution:

​ 我们可以从两个端点向另一点扫 因为可以连续向左也可以连续向右

​ 然后 我们就On求一下两次最长连续下降序列

​ 还有一种做法就是从前扫到后 记录最长连续下降序列和最长连续上升序列(倒过来做)

Code:

int a[200010];
int main()
{
    int n;
    cin >> n;
    rep(i, 1, n + 1)
        cin >> a[i];

    int up = 0, down = 0, res = 0;
    rep(i, 1, n)
    {
        if(a[i] < a[i + 1])    res = max(res, ++ up), down = 0;
        else if(a[i] > a[i + 1])    res = max(res, ++ down), up = 0;        
        else if(a[i] == a[i + 1])    up = 0, down = 0;
    }
    cout << res << endl;
}

L 函数求和(思维)

Description:

题目就是这个意思
∑ i = 1 n m i n L i < = j < = i { g c d ( i , j ) }   m o d ( 1 0 9 + 7 ) \sum_{i=1}^n min_{L_i<=j<=i}\left\{gcd(i,j)\right\}\ mod (10^9+7) i=1nminLi<=j<=i{gcd(i,j)} mod(109+7)
Solution:

​ 因为保证L_i <= j <= ii = L_i的时候 j只能选L_i这点我们是可以确认的

​ 那如何取最小的gcd呢 那我们可以知道gcd(x, x - 1) = 1

​ 所以 我们想到辣 当i != L_i的时候 我们直接选gcd(i, i - 1)就可以了

Code:

int a[10000010];

int main()
{
    int n = read(), m = read();
    for(int i = 1; i <= n; i++)
        a[i] = read();
    
    LL res = 0;
    while(m --)
    {
        int x = read();
        if(x == a[x])   res = (res + x) % mod;
        else res = (res + 1) % mod;
    }
    cout << res;
    return 0;
}

N Raksasa的数字(构造)

Description:

​ 给定数组a 我们可以选择一个数x来对数组内的数全部进行异或

​ 最后要使得数组和最小 当答案有多个x的时候 我们要选择小的x

Solution:

​ 因为异或 让相同的变成0 不同的变成1 所以如果对于一位数来说

​ 0多的话就让这一位异或0 1多的话就让这一位异或1

​ 贪心地构造一下吧 就对于每个数 将其化为二进制格式 然后统计一下每一位是0的个数多还是1的个数多

​ 那什么时候会出现多个x呢 就是当一位数上0和1个数相等 这个时候 异或0和1都是一样的结果 但是因为为了保证x最小 这时候要异或0

​ trick:用bitset可以减少时间复杂度

Code:

int cnt[32];//每一位1的数量
void solve()
{
    vector<bitset<32>> a;
    int n;
    cin >> n;
    rep(i, 0, n)
    {
        int x;
        cin >> x;
        bitset<32> bi(x); //把x化为01串
        a.pb(bi);
    }
    
    ms(cnt, 0);
    rep(i, 0, n)
    {
        rep(j, 0, 32)
            cnt[j] += a[i][j];
    }
    
    LL res = 0;
    rep(i, 0, 32)
    {
        if(cnt[i] > n / 2) //尽量小 所以0和1个数相等的时候不加上这一位
            res += (1LL << i);
    }
    cout << res << endl;
}
举报

相关推荐

0 条评论