1. 程式人生 > 實用技巧 >ZZULI-周賽5題解

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\n", ys, ms, ds); printf("%lld-%lld-%lld\n", 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\n", 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[a[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\n",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\n",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\n", pqwe[le], le2, star);
        else
            printf("%s-%lld\n", 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; }