2021 年百度之星·程序设计大赛 - 初赛二

网址:Contest Problem List (hdu.edu.cn)

1001 签到题 对于文中的坑点,取模后不能为负数,导致迟迟未AC掉,签到题WA掉3次, 浪费了多次罚时
1002 签到题 一次遍历贪心解决即可, 1A
1003 使用并查集解决欧拉路的问题 该问题可以转换为欧拉路的问题,同时使用并查集将整个图分为多个连通图,判断每个连通图是否为欧拉路,若均为欧拉图,则将每个图的度数以及各个图的联通加和即可,其中单个点的连通图未做单独处理导致迟迟不能AC,最终WA掉5次
1004 贪心题(需要将多种情况枚举清楚) 对于问题中的情况,需要对多种情况做出枚举,第一次和第二次遍历情况较为特殊,第三次即以后的情况一样,对不同情况做出区分并加以判断即可,比赛中WA掉3次
1005-1008 1005数学博弈题,1007好像是树形DP 1005-1008比赛时读过问题后放弃解决

 由于很久未做算法题以及未写C++代码,并且多次WA掉,导致思路极为混乱,代码写的极为丑陋。由于昨日参加了初赛一,今日状态较昨日有所提升。继昨日之后再次于签到题WA掉3次,出师不利。AC三道, 罚时6次

1001

该题即为一个求2的n次方的问题,由于数字较大,使用快速幂取模即可,签到。 

 AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 998244353;

ll pow_(ll x, ll y, ll mod)
{
    ll ans = 1;
    ll base = x % mod;
    while(y)
    {
        if(y & 1 != 0)
            ans = ((ans%mod) * (base %mod))%mod;
        y = y >> 1;
        base = ((base%mod) * (base % mod) )%mod;
    }
    return ans % mod;
}


int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        ll a, b, k;
        scanf("%lld%lld%lld", &a, &b, &k);
        ll num = k / 2;
        ll add_ = k % 2;
        ll ansa = a;
        ll ansb = b;
        if(k > 0)
        {
            ansa = ((a%mod) * (pow_(2, num, mod)%mod)) % mod;
            ansb = ((b%mod) * (pow_(2, num, mod)%mod)) % mod;
        }
        if(add_ == 0)
        {
            cout << (ansa + mod)%mod << " " << (ansb + mod)%mod << endl;
        }
        else
        {
            cout << (ansa + ansb + mod)%mod << " " << (ansa - ansb + mod)%mod << endl;
        }
    }
    return 0;
}

1002

 使用sort对数组进行一次排序,再使用一次遍历按照最优的规则即可,签到。

 AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int T;
int a[maxn];


int main()
{
    scanf("%d", &T);
    while(T--)
    {
        int n, k;
        memset(a, 0, sizeof(a));
        scanf("%d%d", &n, &k);
        for(int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
        }
        sort(a, a+n);
        int count_ = 0;
        int min_ = -1e9;
        for(int i=0; i<n; i++)
        {
            int l = a[i] - k;
            int r = a[i] + k;
            if(min_ < l)
            {
                min_ = l;
                count_++;
            }
            else if(min_ >= r)
            {
                continue;
            }
            else if(min_ >= l && min_ < r)
            {
                min_ += 1;
                count_ ++;
            }
        }
        printf("%d\n", count_);
    }

    return 0;
}

1003

 将图中的连通图使用并查集进行分块操作,判断图中结点个数大于2的连通图的数量, 再进行判断每个连通图是否为欧拉图,进行上述两种操作后,对每个连通图的路径个数以及不同联通图的相加即获得正确答案。

 AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;

int val[maxn][maxn];
char str[maxn];
int du[maxn];
int vis[maxn];

int par[maxn]; //父亲
int high[maxn]; //树的高度

void init(int n)
{
    for(int i=0; i<n; i++)
    {
        par[i] = i;
        high[i] = 0;
    }
}

int Find(int x)
{
    return par[x] == x ? x : par[x] = Find(par[x]);
}

void unit(int x,int y)
{
    x = Find(x);
    y = Find(y);
    if(x==y) return ;

    if(high[x]<high[y])
        par[x] = y;
    else
    {
        par[y] = x;
        if(high[x]==high[y])
            high[x] ++;
    }
}


int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int s, n;
        scanf("%d%d", &s, &n);
        n = n - 1;
        memset(val, 0, sizeof(val));
        memset(du, 0, sizeof(du));
        memset(vis, 0, sizeof(vis));
        init(s);
        for(int i=0; i<s - 1; i++)
        {
            scanf("%s", str);
            int len = strlen(str);
            for(int j=0; j<len; j++)
            {
                if(str[j] == '0')
                {
                    val[i+1][j] = 1;
                    val[j][i+1] = 1;
                }
            }
        }
/*
        for(int i=0; i<s; i++)
        {
            for(int j=0; j<s; j++)
            {
                printf("%d ", val[i][j]);
            }
            printf("\n");
        }
*/
        for(int i=0; i<s; i++)
        {
            int count_ = 0;
            for(int j=0; j<s; j++)
            {
                if(val[i][j] == 1)
                {
                    count_++;
                    unit(i, j);
                }
            }
            du[i] = count_;
        }

        int ANS = 0;    //几个连通块
        for(int i=0; i<s; i++)
        {
            vis[Find(i)]++;
        }
        for(int i=0; i<s; i++)
        {
            if(vis[i] >= 2)
            {
                ANS++;
            }
        }
/*
        for(int i=0; i<s; i++)
        {
            printf("%d ", vis[i]);
        }
        printf("\n");

        for(int i=0; i<s; i++)
        {
            printf("%d ", du[i]);
        }
        printf("\n");
*/
        int s_set = Find(n);    //起点的连通集合
        if(vis[s_set] == 1)
        {
            ANS++;
        }
        int s_du = du[n];   //起点的度

        int count_all = 0;
        int ans_all = 0;

        if(s_du % 2 == 1)
        {
            for(int i=0; i<s; i++)
            {
                if(du[i] % 2 == 1)
                {
                    if(Find(i) == s_set)
                    {
                        ans_all += du[i];
                        count_all++;
                        if(count_all >= 3)
                        {
                            ANS = -1;
                            break;
                        }
                    }
                    if(Find(i) != s_set)
                    {
                        ANS = -1;
                        break;
                    }
                }
                else if(du[i] % 2 == 0)
                {
                    ans_all += du[i];
                }
            }
        }
        else
        {
            for(int i=0; i<s; i++)
            {
                if(du[i] % 2 == 1)
                {
                    ANS = -1;
                    break;
                }
                else if(du[i] % 2 == 0)
                {
                    ans_all += du[i];
                }
            }
        }
        if(ANS == -1)
            cout << ANS << endl;
        else
            cout << (ANS - 1) * 2 + ans_all /2 << endl;
    }
    return 0;
}

1004

 贪心算法,使用两种不同的前缀和进行求和计算,计算第一轮遍历后的最大值以及最终值。使用第二种前缀和的方法计算第二次遍历后的最大值以及最终值。第三次及其以后的情况相同。最后分情况讨论即可,比赛过程中WA掉3次,浪费大量时间。

AC代码: 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 100000 + 10;

ll a[maxn];
ll sum[maxn];
ll all[maxn];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {

        ll n, m;
        ll max_ = 0, final_ = 0, sub_ = 0;
        ll max_all = -1e9 - 10;
        scanf("%lld%lld", &n, &m);
        memset(a, 0, sizeof(a));
        memset(sum, 0, sizeof(sum));
        memset(all, 0, sizeof(all));
        for(ll i=0; i<n; i++)
        {
            scanf("%lld", &a[i]);
        }
        if(a[0] < 0)
        {
            sum[0] = 0;
        }
        else
            sum[0] = a[0];
        if(sum[0] > max_)
        {
            max_ = sum[0];
        }

        all[0] = a[0];
        if(all[0] > max_all)
        {
            max_all = all[0];
        }

        for(ll i=1; i<n; i++)
        {
            all[i] = all[i-1] + a[i];
            if(all[i] > max_all)
            {
                max_all = all[i];
            }
            if(all[i] < 0)
            {
                if(all[i] * (-1) > sub_)
                {
                    sub_ = all[i] * (-1);
                }
            }

            sum[i] = sum[i-1] + a[i];
            if(sum[i] < 0)
                sum[i] = 0;
            if(sum[i] > max_)
            {
                max_ = sum[i];
            }
        }
        final_ = sum[n-1];
/*
        //max_all 最大
        //max_ 最大
        // final_ 一轮终止
        // sub_ 回撤
        cout << max_all << endl;
        cout << max_ << endl;
        cout << final_ << endl;
        cout << sub_ << endl;
*/


        if(final_ == 0)
        {
            if(max_ >= m)
            {
                cout << "1" << endl;
            }
            else
            {
                cout << "-1" << endl;
            }
        }
        else if(final_ > 0)
        {
            if(final_ > sub_)
            {
                if(max_ >= m)
                {
                    cout << "1" << endl;
                }
                else
                {
                    if(final_ + max_all >= m)
                    {
                        cout << "2" << endl;
                    }
                    else
                    {
                        ll ans = 0;
                        m = m - max_all;
                        m = m - final_;
                        ll num = m / (final_ - sub_);
                        ll k =m % (final_ - sub_);
                        ans = 2 + num;
                        if(k > 0)
                            ans++;
                        cout << ans << endl;
                    }
                }

            }
            else if(final_ <= sub_)
            {
                if(max_ >= m)
                {
                    cout << "1" << endl;
                }
                else
                {
                    if(final_ + max_all >= m)
                    {
                        cout << "2" << endl;
                    }
                    else if(final_ + max_all < m)
                    {
                        cout << "-1" << endl;
                    }
                }
            }
        }

    }
    return 0;
}

/*
5 5
1 -3 3 2 -2
*/

猜你喜欢

转载自blog.csdn.net/jiangchao98/article/details/119322306