Gym 101964 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)


傳送門

A.Numbers

 

 

B.Broken Watch 

        先考慮最簡單的情況,就是a,b,c都相等的情況,這個時候答案顯然只會跟n有關系,在n個線段里面選3個的情況就是C(n,3),其中有一部分不合法,這個時候考慮怎樣是不合法的,現在設取三條邊分別是x,y,z;當x經過y到達z的這個角的角度小於180度的時候,那么這個方案必然是不合法的,這樣的話只需要確定x和z就可以確定一族不可行的方案,x和z可以夾1....[n/2](上取整)條邊,也就是形成了[n/2](上取整)族答案,每一族的方案數分別是1...[n/2]。於是用總的方案數減去(1+2+3+...+[n/2](上取整))即可。這里的答案是對2^64取模,因此統計答案時要處理一下除法。
        對於a,b,c不相等的情況直接乘上A(3,1)或A(3,3)即可
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
int main(){

    int a,b,c;
    ll n;
    scanf("%d%d%d%llu",&a,&b,&c,&n);
    ll tmp=(n+1)/2;
    tmp-=2;
    ll ans=0;
    //特判除以6的情況
    ll tmp1=n,tmp2=n-1,tmp3=n-2;
    if(tmp1%2==0) tmp1/=2;
    else if((tmp2)%2==0) tmp2/=2;
    if(tmp1%3==0) tmp1/=3;
    else if(tmp2%3==0) tmp2/=3;
    else if(tmp3%3==0) tmp3/=3;
    ans=tmp1*tmp2*tmp3;
    
    ans-=n*(tmp*(tmp+1)/2);
    
    if(a!=b&&b!=c&&c!=a){//全都不相同
        ans*=6;
    }
    else if(a!=b||a!=c||b!=c){//有一個不同
        ans*=3;
    }
    printf("%llu\n",ans);
    return 0;
}
View Code

 


C.Tree

  首先,題目中的”使得最大值最小“這句話就非常符合二分的條件了。因此我們考慮對答案(兩個黑點的最遠的距離)進行二分。

  現在就要考慮如何進行check。

        對於每一個二分值k,我們考慮先用bfs遍歷整顆樹,然后利用bfs的性質(距離當前點的所有已bfs過且小於等於d的那些點,他們之間兩兩距離也小於等於k),找出滿足距離等於k的對應的一個個點集。之后我們可以用dfs去遍歷這些點集,判斷點集中的黑點的個數與需要選取的黑點個數m之間的關系即可(如果數量>=n,則右指針左移動;反之左指針右移)。

#include <bits/stdc++.h>
#define maxn 105
using namespace std;
vector<int>vec[maxn];
int vis[maxn];//用vis數組去區分點的不同的集合
int a[maxn];
queue<int>que;
int n,m;
int ans=0;
int dfs(int now,int fa,int all,int dis){
    int res=a[now];
    if(dis==all) return res;
    for(auto &it:vec[now]){
        if(!vis[it]||it==fa) continue;
        res+=dfs(it,now,all,dis+1);
    }
    return res;
}
bool check(int k){//二分的check,本質上為一個bfs
    memset(vis,0,sizeof(vis));
    while(!que.empty()) que.pop();
    que.push(1);
    while(!que.empty()){//bfs選取部分點集
        int now=que.front();
        que.pop();
        vis[now]=1;
        int tmp=dfs(now,0,k,0);//通過dfs獲取這個集合的黑點的個數
        if(tmp>=m) return 1;
        for(auto &it:vec[now]){
            if(vis[it]) continue;
            que.push(it);
        }
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=0;i<n-1;i++){
        int from,to;
        scanf("%d%d",&from,&to);
        vec[from].push_back(to);
        vec[to].push_back(from);
    }
    int l=0,r=n;
    while(l<r){
        int mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
        //cout<<l<<" "<<r<<endl;
    }
    cout<<r<<endl;
}
View Code

 


 

D.Space Station

 


E.Fishermen

  我們可以先把漁夫的位置排個序,然后遍歷所有的魚,每一條魚能夠被可以被抓都在x軸有一個范圍,通過二分,在漁夫中找到最左的和最右的,然后差分一下,最后求個前綴和就可以得出答案

#include <bits/stdc++.h>
using namespace std;
typedef  long long ll;
const int maxn=2e5+7;
struct SS{
    int x,y;
}a[maxn];
struct S{
    int x,id,idd;
    bool operator <(const S &bb)const {
        return x<bb.x;
    }
}b[maxn];
int sum[maxn],ans[maxn];
int main(){
    //freopen("in.txt","r",stdin);
    int n,m,l;
    scanf("%d %d %d",&n,&m,&l);
    for (int i=1;i<=n;i++)
        scanf("%d %d",&a[i].x,&a[i].y);
    for (int i=1;i<=m;i++) {
        scanf("%d",&b[i].x);
        b[i].id=i;
    }
    sort(b+1,b+m+1);
    for (int i=1;i<=m;i++) b[i].idd=i;
    for (int i=1;i<=n;i++){
        if (a[i].y-l>0) continue;
        S tmp;
        tmp.x=a[i].x-l+a[i].y;
        int xx=lower_bound(b+1,b+m+1,tmp)-b;
        tmp.x=a[i].x+l-a[i].y;
        int yy=upper_bound(b+1,b+m+1,tmp)-b;
        sum[xx]++;
        sum[yy]--;
    }
    for (int i=1;i<=m;i++){
        sum[i]+=sum[i-1];
        ans[b[i].id]=sum[b[i].idd];
    }
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
View Code

 


F.Min Max Convert

 


G.Matrix Queries

 


H.Modern Djinn

 


I.Inversion

  首先,我們要把原序列還原,根據逆序對的性質,還原出原序列。接着,根據題意兩個對集合的定義,可以知道選出的那個點集是從左到右升序的,且點集中最小的點在序列中左邊沒有比它更小的點,最大的點在序列中右邊沒有比它更大的點,所以我們可以進行dp,dp[i]表示以i為點集最后一個點的答案的數量。
  dp轉移見代碼

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=107;
int du[maxn],a[maxn],vis[maxn];
ll dp[maxn];
int main(){
   // freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m,x,y;
    cin>>n>>m;
    while (m--){
        cin>>x>>y;
        du[min(x,y)]++;
    }
    for (int i=1;i<=n;i++){//還原序列
        for (int j=1;j<=n;j++) {
            if (!vis[j]) {
                if (du[i]) du[i]--;
                else {
                    a[i]=j;
                    vis[j]=1;
                    break;
                }
            }
        }
    }
 //   for (int i=1;i<=n;i++) cout<<a[i]<<' ';cout<<endl;
    for (int i=1;i<=n;i++){
        ll res=0,mx=0;
        for (int j=i-1;j;j--){
            if (a[j]>a[i]) continue;// 對答案無貢獻
            if (a[j]>mx) res+=dp[j],mx=a[j];//所有小於mx的值對應位置的dp值都在之前加入到res中了,不再重復加
        }
        dp[i]=max(1ll,res);// 當i前面無比a[i]小的數時,dp[i]為1,它為第一個點也為最后一個點
    }
    ll ans=0,mx=0;
    for (int i=n;i;i--){
        if (a[i]>mx) ans+=dp[i],mx=a[i];//同上mx的解釋
    }
  //  for (int i=1;i<=n;i++) cout<<dp[i]<<' ';cout<<endl;
    cout<<ans<<endl;
    return 0;
}
View Code

 


J.Rabbit vs Turtle

 


K.Points and Rectangles

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM