1. 程式人生 > >Gym.102059: 2018-2019 XIX Open Cup, Grand Prix of Korea(寒假gym自訓第一場)

Gym.102059: 2018-2019 XIX Open Cup, Grand Prix of Korea(寒假gym自訓第一場)

int sin 當前位置 一個 mes span 不存在 src tree

整體來說,這一場的質量比較高,但是題意也有些難懂。

E.Electronic Circuit

題意: 給你N個點,M根線,問它是否是一個合法的電路。

思路: 一個合法的電路,經過一些串聯並聯關系,最後有一個點是正極,一個是負極,我們就來模擬這個串聯的過程即可,並聯的關系會因為我們使用了set而抵消,所以可以不去管它。 模擬串聯: 我們選擇一個度數為2的點,刪去它與兩邊的點u,v的連線,然後連接u-v,知道不存在度數為2的點。 最後當有兩個點度數為1,而且不存在度數為大於大於2的點,則合法。

(選擇set其實比較巧妙,因為不用考慮並聯。

技術分享圖片
#include<bits/stdc++.h>
#define
rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; set<int>S[maxn]; queue<int>q; int main() { int N,M,u,x,y; scanf("%d%d",&N,&M); rep(i,1,M){ scanf("%d%d",&x,&y); S[x].insert(y); S[y].insert(x); } rep(i,
1,N) if(S[i].size()==2) q.push(i); while(!q.empty()){ u=q.front(); q.pop(); if(S[u].size()!=2) continue; x=*S[u].begin(); S[u].erase(S[u].begin()); y=*S[u].begin(); S[u].erase(S[u].begin()); S[x].erase(u); S[y].erase(u); S[x].insert(y); S[y].insert(x);
if(S[x].size()==2) q.push(x); if(S[y].size()==2) q.push(y); } int cnt=0,ok=1; rep(i,1,N) { if(S[i].size()==1) cnt++; if(S[i].size()>1) ok=0; } if(ok&&cnt==2) puts("Yes"); else puts("No"); return 0; }
View Code

F .Fake Plastic Trees

題意:讓你建造一棵樹,使得它有N個葉子節點,而且需要滿足對於每個節點,它的左子樹大小等於右子樹大小,或者左子樹大小比右邊大1。

每次你構造一棵樹,你可以選擇之前構造過的樹作為它的兒子。 現在讓你構造不超過125棵樹,滿足上訴條件。

輸出的方式是,輸出V,表示構造的樹的多少。 接下來V上,每行表示左子樹的標號和右子樹的編號。 最後輸出根節點的標號。

(讀了好久才懂了題意,主要是輸出這裏,我們構造的東西每次都是重復利用了之前的子樹的。

思路:每次除2構造即可。

技術分享圖片
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=100010;
int x[maxn],y[maxn],tot; map<ll,int>mp;
void get(ll num)
{
    if(mp.find(num)!=mp.end()) return ;
    if(num==1LL) {
        x[++tot]=-1; y[tot]=-1; mp[num]=tot;
        return ;
    }
    ll mid=num/2;
    get(num-mid); get(mid);
    tot++;  x[tot]=mp[num-mid]; y[tot]=mp[mid];
    mp[num]=tot;
}
int main()
{
    int T; ll N;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&N);
        tot=-1; mp.clear(); get(N);
        printf("%d\n",tot+1);
        rep(i,0,tot) printf("%d %d\n",x[i],y[i]);
        printf("%d\n",tot);
    }
    return 0;
}
View Code

H .Fractions

題意:求多少對(x,y),滿足A<=x<=B ; C<=y<=D,而且(x+y)/gcd(x,y)<1000;

思路:水題,我們枚舉化簡後的x‘=x/gcd; y‘=y/gcd;然後看有多少gcd可以在給定區間即可。

技術分享圖片
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int main()
{
    ll A,B,C,D,ans=0;
    scanf("%lld%lld%lld%lld",&A,&B,&C,&D);
    rep(i,1,999)
     rep(j,1,999-i){
       if((__gcd(i,j))==1){
          //A<=ix<=B c<=jx<=D
          ll tmp=min(D/j,B/i)-max((A-1)/i,(C-1)/j);
          if(tmp>0) ans+=tmp;
       }
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

I .Game on Plane

題意:給定N個點,圍成一個圈,每次玩家選擇兩個點連線,不得與之前連的線相交。 如果玩家連線形成了一個多邊形或者沒有選的點,輸。

思路:sg函數,每次連線會把大圈分為兩個小圈,跑sg即可。

技術分享圖片
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=5010;
int sg[maxn],vis[maxn];
void init()
{
    sg[1]=0; sg[2]=1;
    rep(i,3,5000){
        rep(j,0,i-2){
            vis[sg[j]^sg[i-2-j]]=i;
        }
        rep(j,0,5000) {
            if(vis[j]!=i) { sg[i]=j; break;}
        }
    }
}
int main()
{
    init();
    int T,N; scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        if(!sg[N]) puts("Second");
        else puts("First");
    }
    return 0;
}
View Code

L .Timsort

題意:給定長度為N的數組a[],Q次詢問,每次給出長度L,讓你按照規定跑。 每次從當前位置出發,一直跑不降序列,或者下降序列。跑完後,如果大於等於L,從下一個位置繼續開始,否則要湊齊長度L,同時累計湊數的個數。

思路:預處理,每次按照規定跑即可,因為我們可以記憶化,所以我們可以假設每次的問題是不一樣的,最壞的情況下是N/1+N/2+N/3...+N/N~=NlogN,所以就ok了,想不到這一點,這個水題就跑掉了。

技術分享圖片
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=100010;
int a[maxn],R[maxn][2],ans[maxn][2];
int main()
{
    int N,Q,x;
    scanf("%d",&N);
    rep(i,1,N) scanf("%d",&a[i]);
    rep2(i,N,1) {
        R[i][0]=R[i][1]=1;
        if(i+1<=N&&a[i]<=a[i+1]) R[i][0]=R[i+1][0]+1;
        if(i+1<=N&&a[i]>a[i+1]) R[i][1]=R[i+1][1]+1;
    }
    scanf("%d",&Q);
    while(Q--){
        scanf("%d",&x);
        if(ans[x][0]) printf("%d %d\n",ans[x][0],ans[x][1]);
        else {
            int A=0,B=0;
            rep(i,1,N){
                A++; if(i==N) break;
                int t=R[i][a[i]>a[i+1]];
                if(t<x){
                    if(i+x-1<=N) B+=x-t;
                    else B+=N-(i+t-1);
                    i=i+x-1;
                }
                else i=i+t-1;
            }
            ans[x][0]=A; ans[x][1]=B;
            printf("%d %d\n",A,B);
        }
    }
    return 0;
}
View Code

Gym.102059: 2018-2019 XIX Open Cup, Grand Prix of Korea(寒假gym自訓第一場)