2014 Benelux Algorithm Programming Contest (BAPC 14)

xzxxzx401發表於2017-10-21

2014 Benelux Algorithm Programming Contest (BAPC 14)

算5題?嘻嘻

Gym - 101512B Button Bashing

水題

#include<bits/stdc++.h>
using namespace std;
const int maxn=7206;
const int inf=0x3f3f3f3f; 

int t[maxn],d[2*maxn];

int main()
{
    int n,m,T;
    cin>>T;
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",t+i);

        queue<int>q;
        pair<int,int> ans=make_pair(inf,inf);
        memset(d,0x3f,sizeof d);
        d[0]=0,q.push(0);

        while(!q.empty()){
            int nd=q.front();
            q.pop();
            if(nd>=m)ans=min(ans,make_pair(nd,d[nd]));
            for(int i=1;i<=n;i++){
                int u=nd+t[i];
                if(u<0)u=0;
                if(u>3600)u=3600;
                if(d[u]==inf)
                    d[u]=d[nd]+1,q.push(u);
            }
        }
        cout<<ans.second<<" "<<ans.first-m<<endl;
    }
    return 0;
}

Gym - 101512E Excellent Engineers

知道樹狀陣列的我哭了起來。
按A維排序,在B處插入C的值,維護區間最小值。查詢時看(1~B)的最小值,有比C小的就加一。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
int n, maxVal;
struct Operation
{
    int a, b, c, w;
    int f;//ans
    bool operator <(const Operation &r)const
    {
        //return a<r.a || (a==r.a&&b<r.b) || (a==r.a&&b==r.b&&c<r.c);
        return (a==r.a&&b==r.b) ? c<r.c : (a==r.a ? b<r.b : a<r.a);
    }
}a[MAXN], t[MAXN];
LL c[MAXN];
inline int lowbit(int x) { return x&-x; }
inline void add(int p, int v) { for(;p<=maxVal;p+=lowbit(p)) c[p]+=v; }
inline LL sum(int p)
{
    LL re=0;
    for(;p;p-=lowbit(p)) re+=c[p];
    return re;
}
int ans[MAXN];
LL rres;
void CDQ(int l, int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    CDQ(l, mid);CDQ(mid+1, r);
    int i=l, j=mid+1, p=l;
    while(i<=mid||j<=r)
    {
        if(j>r||(i<=mid&&a[i].b<=a[j].b)) add(a[i].c, a[i].w), t[p++]=a[i++];
        else a[j].w+=sum(a[j].c), t[p++]=a[j++];
    }
    for(int i=l;i<=mid;i++) add(a[i].c, -a[i].w);
    for(int i=l;i<=r;i++) a[i]=t[i];
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i].a),scanf("%d",&a[i].b),scanf("%d",&a[i].c),a[i].w=1;
        sort(a+1, a+1+n);

        int p=1;
        maxVal=MAXN-1;

        rres=0;
        CDQ(1, n);
        for(int i=1;i<=n;i++)
            if(a[i].w==1) rres++;
        printf("%d\n",rres);
    }
    //system("pause");
}

Gym - 101512I Interesting Integers

數學題,at老譚

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

LL f[49];
LL e_gcd(LL a,LL b,LL &x,LL &y)  
{  
    if(b==0)  
    {  
        x=1;  
        y=0;  
        return a;  
    }  
    LL ans=e_gcd(b,a%b,x,y);  
    LL temp=x;  
    x=y;  
    y=temp-a/b*y;  
    return ans;  
}  

int main()
{
    f[1]=1,f[2]=1;
    for(int i=3;i<=47;i++)
        f[i]=f[i-1]+f[i-2];
    int T;
    LL  n;
    cin>>T;
    while(T--){
        cin>>n;
        LL ansx,ansy;
        ansx=n/2;
        ansy=n-ansx;
        for(int i=3;;i++){
            if(f[i]>n)break;
            LL x=-1,y=-1;
            LL g=e_gcd(f[i-2],f[i-1],x,y);
            if(n%g)continue;
            x*=(n/g),y*=(n/g);
            LL t=(y-x)/(f[i-2]+f[i-1]);
            x=x+t*f[i-1];
            y=y-t*f[i-2];
            if(x>y){
                x-=f[i-1];
                y+=f[i-2];
            }
            if(x<=0 || y<=0)continue;
            if(ansy>y){
                ansy=y,ansx=x;
            }
            else if(ansy==y && ansx>x)
                ansy=y,ansx=x;
        }
        printf("%I64d %I64d\n",ansx,ansy);
    }
    return 0;
}

這時我衝上去寫了一發暴力的K,果然gg。。

Gym - 101512G Growling Gears

大水題,連精度都不卡,不知道為什麼過的人巨少,可能這種訓練賽大家都不削於做水題。。
就是給你一堆拋物線y=ax2+bx+c

y=-ax^2+bx+c
,求最高點。直接頂點公式4acb24a
\frac{4ac-b^2}{4a}

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        double ma;int mai=1;
        for(int i=1;i<=n;i++)
        {
            LL a,b,c;scanf("%I64d %I64d %I64d",&a,&b,&c);
            double fz=-4*a*c-b*b;
            double fm=-4*a;
            if(i==1) ma=fz/fm;
            else
            {
                if(ma<fz/fm)
                {
                    ma=fz/fm;
                    mai=i;
                }
            }
        }
        printf("%d\n",mai);
    }
    //system("pause");
    return 0;
}

在比賽臨結束搞過了A。。

Gym - 101512A Avoiding the Apocalypse

網路流。。根lrj那個運送宇宙超級計算機一模一樣。。按時間拆點,注意細節就好。
超級源向s的0時刻連容量g的邊,表示0時刻初始人數是g。
每個點的時刻t要向t+1連邊,容量無窮,表示可以原地不動。
然後每個醫院的任何時刻都要向超級匯連邊,表示一旦到醫院就算流。
在按時間連其他邊。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
const int oo=0x3f3f3f3f;
struct Dinic
{
    struct Edge{
        int from, to, cap, flow;//cap容量 flow流量
        Edge(){}
        Edge(int u, int v, int c, int f){ from=u;to=v;cap=c;flow=f; }
    };
    vector<Edge> edges;//順序的插入邊
    vector<int> G[MAXN];//儲存邊號
    bool vis[MAXN];//BFS使用
    int d[MAXN];
    int cur[MAXN];
    void init(int n)
    {
        for(int i=0;i<=n;i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));//單向邊第三個引數寫0,雙向邊寫cap
        int t_m=edges.size();
        G[from].push_back(t_m-2);
        G[to].push_back(t_m-1);
    }

    bool BFS(int s, int t)
    {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!Q.empty())
        {
            int x=Q.front();Q.pop();
            for(int i=0;i<G[x].size();i++)
            {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow)//殘量網路
                {
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x, int a, int s, int t)
    {
        if(x==t||a==0) return a;
        int flow=0, _f;
        for(int& i=cur[x];i<G[x].size();i++)
        {
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(_f=DFS(e.to, min(a, e.cap-e.flow), s, t))>0)
            {
                e.flow+=_f;
                edges[G[x][i]^1].flow-=_f;
                flow+=_f;
                a-=_f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        int flow=0;
        while(BFS(s, t))
        {
            memset(cur, 0, sizeof(cur));
            flow+=DFS(s, oo, s, t);
        }
        return flow;
    }
}dinic;
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        int s,g,k;scanf("%d%d%d",&s,&g,&k);
        dinic.init(n*(k+1)+5);
        int m;scanf("%d",&m);
        int super_s=(k+1)*n+1;
        int super_t=(k+1)*n+2;

        dinic.AddEdge(super_s,s,g);
        while(m--)
        {
            int tmp;
            scanf("%d",&tmp);
            for(int i=0;i<=k;i++)
                dinic.AddEdge(tmp+n*i,super_t,g);
        }
        for(int i=1;i<=n;i++)
            for(int j=0;j<k;j++)
            {
                dinic.AddEdge(i+n*j,i+n*(j+1),g);
            }
        int r;scanf("%d",&r);
        for(int i=1;i<=r;i++)
        {
            int a,b,p,t;scanf("%d%d%d%d",&a,&b,&p,&t);
            int tm=0;
            while(tm+t<=k)
            {
                dinic.AddEdge(a+n*(tm),b+n*(tm+t),p);
                tm++;
            }
        }
        int res=dinic.Maxflow(super_s,super_t);
        printf("%d\n",min(res,g));
    }
    //system("pause");
    return 0;
}

開始賽後補題。。說實話感覺D也不難,要是我當時不寫K的暴力或許就能出了。。

Gym - 101512D Dropping Directions

這題很蛇皮,樣例巨難畫。不過耐著心畫下來,實際每個點度都是4。我們假設一個路標都不設定,從目標點開始搜尋,那麼會搜出兩個尤拉回路。因為目標點度是4,一個入一個出,所以會有兩個迴路。模擬樣例2和樣例3(因為他倆圖一樣,省事),發現剩下的尤拉回路一個迴路添一個路標就可以了,因為一個路標就可以讓這條迴路全指向通往目標點的迴路。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
int vis[MAXN][4];
int to[MAXN][4];
int go(int p,int f)
{
    if(to[p][0]==f) {vis[p][0]=1,vis[p][2]=1;return to[p][2];}
    if(to[p][1]==f) {vis[p][1]=1,vis[p][3]=1;return to[p][3];}
    if(to[p][2]==f) {vis[p][2]=1,vis[p][0]=1;return to[p][0];}
    if(to[p][3]==f) {vis[p][3]=1,vis[p][1]=1;return to[p][1];}
    assert("No Way!");
}
queue<pair<int,int>> que;
void sousuo(int u,int i)
{
    if(!vis[u][i])
        {
            int now=to[u][i],la=u;vis[u][i]=1;
            while(1)
            {
                int v=go(now,la);
                la=now,now=v;
                if(now==u)
                {
                    for(int j=0;j<4;j++)
                        if(to[u][j]==la) vis[u][j]=1;
                    break;
                }
            }
        }
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        int n,s;scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&to[i][0],&to[i][1],&to[i][2],&to[i][3]);
        }
        for(int i=0;i<4;i++)
            if(!vis[s][i])
                sousuo(s,i);
//        for(int i=1;i<=n;i++)
//        {
//            printf("%d  ",i);
//            for(int j=0;j<4;j++)
//            {
//                printf("%d:%d ",to[i][j],vis[i][j]);
//            }
//            printf("\n");
//        }
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(!vis[i][j])
                    sousuo(i,j),cnt++;
            }
        }
        printf("%d\n",cnt);
    }
    //system("pause");
    return 0;
}

Gym - 101512C Citadel Construction

凸包的最大內接四邊形,旋轉卡殼法。程式碼太長了,不貼了。

Gym - 101512K Key to Knowledge

正解是折半搜尋。用空間換時間,將前一半215

2^{15}
的結果存到map裡面,搜尋後一半時去裡面查詢。

#include<bits/stdc++.h>
using namespace std;

string ans[15];
int grade[15];
map<string, pair<int, long long>> rec;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n, m;
        cin>>n>>m;
        rec.clear();
        for(int i=1;i<=n;i++)
        {
            cin>>ans[i]>>grade[i];
        }
        int mid=m/2;
        for(long long a=0;a<(1ll<<mid);a++)
        {
            string status="";

            for(int i=1;i<=n;i++)
            {
                int p=0;
                long long aa=a;
                for(int j=0;j<mid;j++)
                {
                    if((aa&1)==ans[i][j]-'0') p++;
                    aa>>=1;
                }
                int relase=grade[i]-p;
                if(relase<0) break;
                status+='0'+relase;
            }
            if(status.size()==n)
            {
                rec[status].first++;
                rec[status].second=a;
            }
        }
        long long solution=0;
        long long left, right;
        for(long long a=0;a<(1ll<<(m-mid));a++)
        {
            string status="";
            for(int i=1;i<=n;i++)
            {
                int p=0;
                long long aa=a;
                for(int j=mid;j<m;j++)
                {
                    int nb=ans[i][j]-'0';
                    if((aa&1)==nb) p++;
                    aa>>=1;
                }
                int relase=grade[i]-p;
                if(relase<0) break;
                status+='0'+p;
            }
            if(status.size()==n)
            {
                auto it=rec.find(status);
                if(it!=rec.end())
                {
                    solution+=it->second.first;
                    left=it->second.second;
                    right=a;
                }
            }

        }
        if(solution==1)
        {
            string ans="";
            for(int i=0;i<mid;i++)
            {
                ans+='0'+(left&1);
                left>>=1;
            }
            for(int i=mid;i<m;i++)
            {
                ans+='0'+(right&1);
                right>>=1;
            }
            cout<<ans<<'\n';
        }
        else
        {
            cout<<solution<<" solutions\n";
        }
    }
    return 0;
}

剩下的,J是個水題模擬,剩下兩個沒看,好像題解都沒有。。。

相關文章