1. 程式人生 > >2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest(部分題解)

2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest(部分題解)

傳送門

Problem A:Secret of Chocolate Poles
思路:簡單dp。d[i][0/1]d[i][0/1]表示高度為i時,頂層圓盤是0/1顏色時的方案數。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll d[110][2];
int main()
{
    int n,k;
    cin>>n>>k;
    memset(d,0,sizeof d);
    d[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        d[i][0]+=d[i-1][1];
        d[i][1]+=d[i-1][0];
        if(i>=k)d[i][1]+=d[i-k][0];
    }
    ll ans=0;
    for(int i=1;i<=n;i++)ans+=d[i][1];
    cout<<ans<<endl;
    return 0;
}

Problem B:Parallel Lines
思路:首先預處理出子集f[i][j]f[i][j],表示線段集合為ii且有一條線段為jj時,這個子集裡面的所有線段之間互相平行的對數。
然後狀壓列舉子集求答案。
理論複雜度為O(2n120n2+3n)O(2^n*120*n^2+3^n),但實際上預處理的過程中有許多無效狀態。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Point{int x,y;}p[20],tp[125];
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}
int operator^(Point A,Point B){return A.x*B.y-A.y*B.x;}
int f[1<<16][125];
int ans[1<<16];
int main()
{

    int n;
    cin>>n;
    for(int i=0;i<n;i++)scanf("%d%d",&p[i].x,&p[i].y);
    int cnt=0;
    memset(f,-1,sizeof f);
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    {
        cnt++;
        f[(1<<i)^(1<<j)][cnt]=0;
        tp[cnt]=p[i]-p[j];
    }
    for(int i=0;i<(1<<n);i++)//預處理
    {
        int num=__builtin_popcount(i);
        for(int j=1;j<=cnt;j++)
        {
            if(f[i][j]==-1)continue;
            for(int k=0;k<n;k++)
            {
                if((1<<k)&i)continue;
                for(int h=k+1;h<n;h++)
                {
                    if((1<<h)&i)continue;
                    if((p[k]-p[h])^tp[j])continue;
                    f[i^(1<<k)^(1<<h)][j]=max(f[i^(1<<k)^(1<<h)][j],f[i][j]+num/2);
                }
            }
        }
    }
    for(int i=0;i<(1<<n);i++)
    for(int j=1;j<=cnt;j++)f[i][0]=max(f[i][0],f[i][j]);
    for(int i=0;i<(1<<n);i++)
    {
        int S=((1<<n)-1)^i;
        for(int j=S;j;j=(j-1)&S)
        {
            ans[i^j]=max(ans[i^j],ans[i]+f[j][0]);
        }
    }
    cout<<ans[(1<<n)-1]<<endl;
    return 0;
}

Problem C:Medical Checkup
思路:推一下,可以發現一個人的h值影響著以後的人的檢查時間,最後一個人依次檢查完的時間是一個等差數列,注意t=0的情況。(用二分可以避免)

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
typedef long long ll;
ll h[MAX];
int main()
{
    ll n,t;
    cin>>n>>t;
    for(int i=1;i<=n;i++)scanf("%lld",&h[i]);
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        sum+=h[i];
        ll d=max(h[i],h[i-1]);
        ll l=1,r=1e9+10,ans=1;
        while(r>=l)
        {
            ll m=(l+r)/2;
            if(sum+d*(m-1)>t)
            {
                r=m-1;
                ans=m;
            }
            else l=m+1;
        }
        h[i]=d;
        printf("%lld\n",ans);
    }
    return 0;
}

Problem I:Starting a Scenic Railroad Service

思路:第一種情況的答案就是對於所有線段,與其有公共區間的線段數量的最大值就是答案。
求與一條線段有公共區間的線段數量,對所有線段按左端點排序,二分求出所有左端點在該線段裡的線段數量,然後再用主席樹求出右端點在該線段裡的線段數量,累加即時答案。
第二種情況用差分,然後累加和的最大值就是答案。

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
vector<int>v;
struct lenka
{
    int L,R,sum;
}A[MAX*40];
int tot,root[MAX],a[MAX];
void init()
{
    tot=1;
    root[0]=0;
    A[0].L=A[0].R=A[0].sum=0;
}
void build(int x,int&rt,int l,int r)
{
    A[tot++]=A[rt];
    rt=tot-1;
    A[rt].sum++;
    if(l==r)return;
    if(x<=(l+r)/2)build(x,A[rt].L,l,(l+r)/2);
    else build(x,A[rt].R,(l+r)/2+1,r);
}
int ask(int l,int r,int x,int y,int k)
{
    if(l==r)return A[y].sum-A[x].sum;
    if(k>(l+r)/2)return ask((l+r)/2+1,r,A[x].R,A[y].R,k);
    return A[A[y].R].sum-A[A[x].R].sum+ask(l,(l+r)/2,A[x].L,A[y].L,k);
}
int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
struct Point{int x,y;}p[MAX],B[MAX];
int cmpx(const Point&x,const Point& y)
{
    if(x.x==y.x)return x.y<y.y;
    return x.x<y.x;
}
int n;
int f(int x)
{
    int l=1,r=n,ans=0;
    while(r>=l)
    {
        int m=(l+r)/2;
        if(B[m].x<x)
        {
            l=m+1;
            ans=m;
        }
        else r=m-1;
    }
    return ans;
}
int sum[MAX];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].x,&p[i].y);
        sum[p[i].x]++;
        sum[p[i].y]--;
    }
    for(int i=1;i<=n;i++)B[i]=p[i];
    sort(B+1,B+n+1,cmpx);
    init();
    for(int i=1;i<=n;i++)v.push_back(B[i].y);
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i=1;i<=n;i++)
    {
        root[i]=root[i-1];
        build(getid(B[i].y),root[i],1,n);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int R=f(p[i].y);
        int L=f(p[i].x);
        ans=max(ans,max(0,R-L)+ask(1,n,root[0],root[L],getid(p[i].x+1)));
    }
    for(int i=1;i<=100000;i++)sum[i]+=sum[i-1];
    printf("%d %d\n",ans,*max_element(sum+1,sum+100001));
    return 0;
}