zoukankan      html  css  js  c++  java
  • ZZULI-周赛5题解

    其实比赛我们三都觉得出的没问题的,但还是出锅了,不止是难度不对口,而且比赛期间A题数据出错了,一直在改数据,到最后才改完。。。

    先向各位新生同学说声抱歉吧,没给你们好的周赛体验.如果再来一次,肯定还给你们搞成这样,应该会好好出点有梯度的题目.

    本次出题人实力有限,望各位大佬踊跃提出问题和指导,狗头.

    A:

      题型:水题(出题人原话

      思路:小模拟小模拟...就需要注意一下闰年还是非闰年...亿点点小细节

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define debug(x) cout << #x << "=" << x << endl
    #define debug2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
    //   *(ve._M_impl._M_start)@(ve.size())
    char *p[] = {"NO", "YES"};
    const int mod = 1e9 + 7;
    const int maxn = 1e5 + 7;
    ll day_run[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    ll day_pin[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    ll pan(ll y)
    {
        if (y % 4 == 0 && y % 100 != 0)
        {
            return 1;
        }
        else if (y % 400 == 0)
        {
            return 1;
        }
        return 0;
    }
    void add(ll &y, ll &m, ll &d)
    {
        d++;
        if (pan(y))
        {
            if (day_run[m] < d)
            {
                m++;
                d = 1;
            }
            if (m > 12)
            {
                y++;
                m = 1;
            }
        }
        else
        {
            if (day_pin[m] < d)
            {
                m++;
                d = 1;
            }
            if (m > 12)
            {
                y++;
                m = 1;
            }
        }
    }
    ll hanyou(ll &y, ll &m, ll &d, ll &y2, ll &m2, ll &d2)
    {
        ll s = y * 10000 + m * 100 + d;
        ll s2 = y2 * 10000 + m2 * 100 + d2;
        if (s <= s2)
        {
            return 1;
        }
        return 0;
    }
    int main()
    {
        ll y, m, d, n, i, a, b, c, sh = 14, lo = 66;
        ll ys, ms, ds, yl, ml, dl;
        scanf("%lld-%lld-%lld", &y, &m, &d);
        ys = yl = y;
        ms = ml = m;
        ds = dl = d;
        for (i = 1; i < sh; i++)
        {
            add(ys, ms, ds);
        }
        for (i = 1; i < lo; i++)
        {
            add(yl, ml, dl);
        }
        scanf("%lld", &n);
        for (i = 0; i < n; i++)
        {
            scanf("%lld-%lld-%lld", &a, &b, &c);
            if (hanyou(a, b, c, ys, ms, ds))
            {
                add(ys, ms, ds);
            }
            if (hanyou(a, b, c, yl, ml, dl))
            {
                add(yl, ml, dl);
            }
        }
        printf("%lld-%lld-%lld
    ", ys, ms, ds);
        printf("%lld-%lld-%lld
    ", yl, ml, dl);
        return 0;
    }

    B:略

    C: 

      题型:思维题...

      思路:对于数组中第 i 个元素考虑计算次数,当前元素只被前 i - 1 个元素乘一遍(记得取余操作,还有long long避免数据溢出).

         前后缀都可以做到.

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    typedef  long long ll;
    ll a[maxn],sum[maxn];
    const int mod = 1e9 + 7;
    
    int main(){
        int n;cin >> n;
        for(int i = 1;i <= n;i++) {
            cin >> a[i];
            sum[i] = sum[i - 1] + a[i];
            sum[i] %= mod;
        }
        ll ans = 0;
        for(int i = 2;i <= n;i++){
            ans = (ans + a[i] * sum[i-1]) % mod;
        }
        cout << ans % mod<< endl;
        return 0;
    }

    D:

      题型:思维题...(题面可能没解释清楚...我的锅)

      思路:对于 i ( 0 < i <= n) 来说,A[ i ]就是被引用 i 次的文章个数,那么可以考虑从 i = n 循环到i == 0.维护当前 i ~ n 之间的和 sum,当满足 sum >= i 就是题目要求的答案,输出当前 i 即可.

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5 + 100;
    
    int n, a[maxn];
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n + 1; i++)
            scanf("%d", &a[i]);
        ll sum = a[n + 1];
        for (int i = n; i >= 0; i--)
        {
            if (sum >= i)
            {
                printf("%d
    ", i);
                break;
            }
            sum += a[i];
        }
        return 0;
    }

    E:

      题型:数学知识...

      思路:

        设 x <= y,当 x == y 时,原式出成立,所以x < y。

        因为x < y + GCD ( x , y )  <  y,所以 x + y + GCD ( x , y )  <  3y,又因为 x + y + GCD ( x , y )  > y 且 LCM ( x , y ) 是 y 的整数倍,所以 x < y + GCD ( x , y )  = 2y,且 LCM ( x , y ) = 2y。

        因为 x * y =GCD ( x , y ) * LCM ( x , y ) ,所以 x * y = 2y * GCD ( x , y ),得到 GCD ( x , y ) = x / 2;带回原式得 x + y + x / 2 = 2y,解得 x  = 2 / 3y或者 y = 3/2x。

        由以上结论得,对于每个偶数x,满足 x + y +GCD ( x , y ) = LCM ( x , y ) 且大于 x 的 y 有且只有一个,即 y = 3 / 2x。而奇数则不存在这样的y。

        所以将选出来的数从小到大排序,去重,一定满足 bi  =  2 / 3b( i + 1) (1 <= i <= k)。

    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #define N 200000
    int n,a[N],ans = -1,b[N];
    int main(void){
        scanf("%d",&n);
        for(int i = 0;i<n;i++){
            scanf("%d",&a[i]);
            b[a[i]]++;   //通过 b 数组来统计 a[i]的个数
        }
        for(int i = 0;i < n;i++){      //冒泡排序
            for(int j = 0;j <n-1-i;j++){
                if(a[j]>a[j+1]){
                    int temp = a[j];
                    a[j] =a[j+1];
                    a[j+1] =temp;
                }
            }
        }

        for(int i = 0;i<n;i++){
            int temp = a[i],sum = 0;
            while(b[temp]){   //从数组中取出一个数,然后在 while 训中改变数值;
                sum +=temp*b[temp];   //当该数存在时,进行循环,sum 统计存在的值,该值要 乘上其个数
                if(temp%2==0)     //更加推论,如果该数是偶数,则寻找对应的 y 值,
                temp = temp/2*3;
                else
                break;
            }
            if(sum>ans)    //获得最大的累加之积
            ans =sum;
        }
        printf("%d ",ans);
        return 0;
    }

    F:

      题型:模拟...

      思路:直接模拟接水过程,刚开始时让m个水龙头都开着,m个同学都在接水,一旦有一个同学接完了,下一个同学就立刻来这个水龙头接水。

    #include<stdio.h>
    #include<math.h>
    #include<stdlib.h>
    #define N 200000
    int a[N],b[N],n,m,t,ans;
    int main(void){
        scanf("%d %d",&n,&m);
        for(int i = 1;i<=n;i++)
        scanf("%d",&a[i]);
        t = m + 1;  //记录等待接水的队伍中的第一个学生的编号
        while(t<=n+m){
            for(int i = 1;i<=m;i++){    //枚举m个水龙头,在一次循环结束后,
    //接水的m个同学的要接的水的量减一
                a[i]--;          
                if(!a[i]){               //如果有个同学接完水了,下一个同学补上
                    a[i] =a[t];
                    t++;            
                }
            
            }
            ans++;                //当for循环结束后,表示模拟的时间为1秒,ans加一
        } 
        printf("%d
    ",ans);
        return 0;
    } 

    G:

      题型:模拟...

      思路:直接根据题意模拟,标记小K学长和女神吃到第几个糖果,以及他们所用的时间,如果女神当前的时间小于等于小K学长的时间,则女神开始吃下一个,否则小K学长开始吃下一个。

    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #define N 100000
    int n, a[N], l, r, sum1, sum2;
    
    int main(void)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        l = 1, r = n; //l代表女神吃到糖果的位置,r代表小K迟到的糖果的位置
        while (l <= r)
        {
            if (sum1 <= sum2)
            { //sum1代表女神所用的时间,sum2代表小K学长所用的时间, sum1 +=a[l++];          //如果sum1<=sum2,则女神开始吃下一个糖果
                sum1 += a[l++];
            }
            else
            {
                sum2 += a[r--];
            }
        }
        printf("%d %d", l - 1, n - l + 1); //l-1表示女神吃到的糖果的位置,因为女神是从前往后开始  //吃的,所以l-1也表示女神吃了几个,那么剩下的就代表小K学长吃的糖果数。
        return 0;
    }

    H:

      题型:大模拟(手动狗头

      思路:直接模拟呀!!!(来自队友大佬的原话

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    char *p[] = {"NO", "YES"};
    const int mod = 1e9 + 7;
    const int maxn = 1e5 + 7;
    ll jiafen(ll liansheng, ll jili[])
    {
        if (liansheng > 5)
        {
            liansheng = 5;
        }
        return jili[liansheng];
    }
    char *pqwe[] = {"", "Bronze", "Silver", "Gold", "Platinum", "Diamond", "Star", "the strongest king"};
    int main()
    {
        char a[2000];
        while (~scanf("%s", a))
        {
            ll liststar[] = {0, 3, 3, 4, 4, 5, 5, 200};
            ll listduan[] = {0, 3, 3, 4, 5, 5, 5, 1};
            ll jili[] = {0, 0, 8, 13, 18, 23};
            ll le = 1, le2 = 1, star = 0, i, len, integral = 0, card = 0;
            ll jifenwin = 10, liansheng;
    
            len = strlen(a);
            liansheng = 0;
            for (i = 0; i < len; i++)
            {
                if (a[i] == 'W')
                {
                    liansheng++;
                    star++;
                    integral += jifenwin;
                    integral += jiafen(liansheng, jili);
                    if (integral >= 350)
                    {
                        integral -= 350;
                        star++;
                    }
                    if (star > liststar[le])
                    {
                        star -= liststar[le];
                        le2++;
                        if (le2 > listduan[le])
                        {
                            le2 -= listduan[le];
                            le++;
                            card += 2;
                        }
                    }
                }
                else
                {
                    liansheng = 0;
                    if (le == 1)
                    {
                        continue;
                    }
                    else if (le == 2 && le2 == 1 && star == 0)
                    {
                        continue;
                    }
                    if (card)
                    {
                        card--;
                    }
                    else if (integral >= 150)
                    {
                        integral = 0;
                    }
                    else
                    {
                        star--;
                        if (star < 0)
                        {
                            le2--;
                            if (le2 < 1)
                            {
                                le--;
                                le2 = listduan[le];
                            }
                            star = liststar[le] - 1;
                        }
                    }
                }
            }
            if (le != 7)
                printf("%s-%lld-%lld
    ", pqwe[le], le2, star);
            else
                printf("%s-%lld
    ", pqwe[le], star);
        }
        return 0;
    }

    I:

      题型:DP...(想当防AK题的

      思路:对于第二个答案,就是数组中最长上升子序列的长度,因为对于第 i 个元素,如果没有比前 i - 1 个元素小,那么必然需要再多一个导弹系统来放出更高的防空导弹来防卫,即就数组中最长上升子序列的长度.

            对于第一个答案,就是反向数组最长非下降子序列的长度 .

           哈?你问我什么事最长上升子序列?建议百度,我太菜了...

    // 输入可以使用简单的 while(scanf("%d",&a[i]) != EOF) 
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    
    int dp[100005];
    int main(){
        string s;getline(cin,s);
        stringstream ss;
        ss << s;
        vector<int> q;
        int x;
        while(ss >> x) q.push_back(x);
       // 输入可以使用简单的 while(scanf("%d",&a[i]) != EOF)
    int n = q.size(); for(int i = 0;i <= n;i++) dp[i] = inf; for(int i = 0;i < q.size();i++){ *lower_bound(dp,dp+n,q[i]) = q[i]; } int cnt = lower_bound(dp,dp+n,inf) - dp; reverse(q.begin(),q.end()); for(int i = 0;i <= n;i++) dp[i] = inf; for(int i = 0;i < q.size();i++){ *upper_bound(dp,dp+n,q[i]) = q[i]; } cout << lower_bound(dp,dp+n,inf) - dp << endl; cout << cnt <<endl; return 0; }
  • 相关阅读:
    UVA Live Achrive 4327 Parade (单调队列,dp)
    从磁盘读取一个文件到内存中,再打印到控制台
    二分查找法
    日期:Date
    线程与进程
    泛型基本知识
    泛型
    Map集合的遍历方式:
    Arrays
    Set接口
  • 原文地址:https://www.cnblogs.com/Wise-XiaoWei4/p/14057838.html
Copyright © 2011-2022 走看看