2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest(部分題解)
阿新 • • 發佈:2018-12-21
Problem A:Secret of Chocolate Poles
思路:簡單dp。表示高度為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
思路:首先預處理出子集,表示線段集合為且有一條線段為時,這個子集裡面的所有線段之間互相平行的對數。
然後狀壓列舉子集求答案。
理論複雜度為,但實際上預處理的過程中有許多無效狀態。
#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;
}