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; }
原文地址:https://www.cnblogs.com/Wise-XiaoWei4/p/14057838.html