Asia Hong Kong Regional Contest 2016
A. Colourful Graph
可以在$2n$步之内实现交换任意两个点的颜色,然后就可以构造出方案。
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL;
const int mod=1e9+7,Maxn=222;
const LL Inf=1LL<<60;
int n,m,K;
int col[Maxn],col2[Maxn];
int done[Maxn],pre[Maxn];
vector<int>G[Maxn];
vector<int> way[102][102];//i->j
int fst[222];
void bfs(int st){
for(int i=1;i<=n;i++)done[i]=i==st?1:0;
queue<int>q;
q.push(st);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
int v=G[u][i];if(done[v])continue;
done[v]=1;
pre[v]=u;
q.push(v);
}
}
for(int i=1;i<=n;i++){
int u=i;
way[st][i].clear();
for(;u!=st;u=pre[u])way[st][i].push_back(u);
way[st][i].push_back(st);
reverse(way[st][i].begin(),way[st][i].end());
}
}
void pt(){
for(int i=1;i<=n;i++)printf("%d%c",col[i],i==n?'\n':' ');
}
void swp(int st,int ed,int ty){
vector<int>tmp=way[st][ed];
for(int i=0;i<tmp.size()-1;i++){
if(i==tmp.size()-2){
if(ty)col[tmp[i+1]]=col[tmp[i]];
else swap(col[tmp[i+1]],col[tmp[i]]);
}
else swap(col[tmp[i]],col[tmp[i+1]]);
pt();
}
for(int i=tmp.size()-2;i>0;i--){
swap(col[tmp[i]],col[tmp[i-1]]);
pt();
}
}
void solve () {
for(int i=1;i<=n;i++)scanf("%d",col+i),G[i].clear();
for(int i=1;i<=n;i++)scanf("%d",col2+i);
for(int i=0;i<m;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
//puts("ok");
bool flag=1;
for(int i=1;i<=n;i++){
int t=0;
for(int j=1;j<=n;j++)if(col2[i]==col[j]){t=1;break;}
if(!t){flag=0;break;}
}
if(!flag){
puts("Impossible");
return;
}
pt();
for(int i=1;i<=n;i++)bfs(i); memset(fst,0,sizeof fst);
for(int i=1;i<=n;i++){
if(!fst[col2[i]]){
fst[col2[i]]=i;
if(col[i]==col2[i])continue;
for(int j=1;j<=n;j++){
if(col[j]==col2[i]){
swp(j,i,0);
break;
}
}
}
}
for(int i=1;i<=n;i++){
if(col[i]!=col2[i])swp(fst[col2[i]],i,1);
}
} int main () {
while ( ~scanf ( "%d%d%d" , &n,&m,&K ) ) solve () ;
return 0 ;
}
B. Doors
答案就是这些折线之间距离的最小值除以2。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std; double R,L,W,Alpha,Beta;
int Case; const double pi=acos(-1.0),eps=1e-9,inf=10000.0; int sgn(double x){
if(x<-eps)return -1;
if(x>eps)return 1;
return 0;
}
struct P{
double x,y;
P(){x=y=0;}
P(double _x,double _y){x=_x,y=_y;}
P operator+(P v){return P(x+v.x,y+v.y);}
P operator-(P v){return P(x-v.x,y-v.y);}
double operator*(P v){return x*v.x+y*v.y;}
double len(){return hypot(x,y);}
};
double cross(P a,P b){return a.x*b.y-a.y*b.x;} double dist_point_to_segment(P p,P a,P b){
if(sgn((p-a)*(b-a))>=0&&sgn((p-b)*(a-b))>=0)
return fabs(cross(p-a,b-a))/(b-a).len();
return min((p-a).len(),(p-b).len());
} double cal(P a,P b,P c,P d){
return min(min(dist_point_to_segment(a,c,d),
dist_point_to_segment(b,c,d)),
min(dist_point_to_segment(c,a,b),
dist_point_to_segment(d,a,b)));
} double solve(){
P A(-inf,W),B(0,W);
P D(L,W),E(inf,W);
P G(L,0),H(inf,0);
Alpha=pi-Alpha,Beta=pi-Beta;
P C=D+P(cos(Alpha)*L,sin(Alpha)*L);
P F=G+P(cos(Beta)*L,sin(Beta)*L);
double ans=min(L,W);
ans=min(ans,cal(A,B,C,D));
ans=min(ans,cal(C,D,F,G));
ans=min(ans,cal(D,E,F,G));
ans/=2.0;
ans=min(ans,R);
ans=max(ans,0.0);
return ans;
} int main(){
scanf("%lf%lf%lf",&R,&L,&W);
scanf("%d",&Case);
while(Case--){
scanf("%lf%lf",&Alpha,&Beta);
printf("%.9f\n",solve());
}
return 0;
}
C. Peak Tower
求出所有线段相交的时刻,在相邻时刻里三分答案即可。时间复杂度$O(n^4\log n)$。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2000;
const double eps=1e-9;
double W,H,E,ans=1e9;
int n,i,j;
struct Rec{
double w,h,sx,sy,vx,vy;
void read(){
scanf("%lf%lf%lf%lf%lf%lf",&w,&h,&sx,&sy,&vx,&vy);
}
}a[N];
int sgn(double x){
if(x<-eps)return -1;
if(x>eps)return 1;
return 0;
}
int m,cnt;
double vipy[N];
int cov[N];
double ct[1000000];
int cntt;
struct Ev{
double x,l,r;int p;
Ev(){}
Ev(double _x,double _l,double _r,int _p){x=_x,l=_l,r=_r,p=_p;}
}e[N];
inline bool cmp(const Ev&a,const Ev&b){
return a.x<b.x;
}
double cal(double Time){
//if(Time<-eps||Time>E+eps)return;
int i,j;
m=0;
for(i=1;i<=n;i++){
double xl=a[i].sx+a[i].vx*Time,
xr=xl+a[i].w,
yl=a[i].sy+a[i].vy*Time,
yr=yl+a[i].h;
xl=min(max(xl,0.0),W);
xr=min(max(xr,0.0),W);
yl=min(max(yl,0.0),H);
yr=min(max(yr,0.0),H);
//printf("%.8f %.8f %.8f %.8f\n",xl,xr,yl,yr);
if(xl+eps>xr||yl+eps>yr)continue;
vipy[++m]=yl;
e[m]=Ev(xl,yl,yr,1);
vipy[++m]=yr;
e[m]=Ev(xr,yl,yr,-1);
}
double ret=0;
if(!m){
//printf("fuck %.8f %.8f\n",Time,0.0);
ans=0;
return 0;
}
sort(vipy+1,vipy+m+1);
sort(e+1,e+m+1,cmp);
for(i=1;i<m;i++)cov[i]=0;
for(i=1;i<=m;i++){
if(i>1){
for(j=1;j<m;j++){
if(cov[j]>0)ret+=(vipy[j+1]-vipy[j])*(e[i].x-e[i-1].x);
}
}
if(ret>ans)return ret;
double l=e[i].l,r=e[i].r;
//printf("ev %.8f %.8f %.8f %d\n",e[i].x,l,r,e[i].p);
for(j=1;j<m;j++){
double A=vipy[j],B=vipy[j+1];
if(sgn(A-l)>=0&&sgn(B-r)<=0){
cov[j]+=e[i].p;
}
}
}
//printf("%.8f %.8f\n",Time,ret);
ans=min(ans,ret);
return ret;
}
inline bool check(double Time){
if(Time<-eps||Time>E+eps)return 0;
return 1;
}
void deal(double A,double B,double C,double D){
A-=C;
B-=D;
A=-A;
if(!sgn(B))return;
if(check(A/B))ct[++cntt]=A/B;
}
void search(double l,double r){
cal(r);
double m1,m2,s1,s2;
int step=0;
while(l+1e-5<r&&step++<10){
m1=l+(r-l)/3.0;
m2=r-(r-l)/3.0;
s1=cal(m1);
s2=cal(m2);
if(s1<s2)r=m2-eps;else l=m1+eps;
}
}
int main(){
scanf("%d%lf%lf%lf",&n,&W,&H,&E);
for(i=1;i<=n;i++)a[i].read();
ct[++cntt]=0;
ct[++cntt]=E;
a[n+1].w=W;
a[n+1].h=H;
for(i=1;i<=n+1;i++)
for(j=i+1;j<=n+1;j++){
deal(a[i].sx ,a[i].vx,a[j].sx ,a[j].vx);
deal(a[i].sx+a[i].w,a[i].vx,a[j].sx ,a[j].vx);
deal(a[i].sx ,a[i].vx,a[j].sx+a[j].w,a[j].vx);
deal(a[i].sx+a[i].w,a[i].vx,a[j].sx+a[j].w,a[j].vx); deal(a[i].sy ,a[i].vy,a[j].sy ,a[j].vy);
deal(a[i].sy+a[i].h,a[i].vy,a[j].sy ,a[j].vy);
deal(a[i].sy ,a[i].vy,a[j].sy+a[j].h,a[j].vy);
deal(a[i].sy+a[i].h,a[i].vy,a[j].sy+a[j].h,a[j].vy);
}
//cal(5);
sort(ct+1,ct+cntt+1);
cal(0);
for(i=1;i<=cntt;i++)if(ct[i]>ct[i-1]+eps){
search(ct[i-1],ct[i]);
}
printf("%.10f",ans);
}
D. Peak Tram
每个位置最多$O(n^2)$种可能的高度,然后DP即可。
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL;
const int mod=1e9+7,Maxn=71;
const LL Inf=1LL<<60;
vector<LL>V;
LL p[Maxn],c[Maxn];
LL dp[2][142*71][71];
LL pre[2][142*71][71];
int getid(LL x){
return lower_bound(V.begin(),V.end(),x)-V.begin();
}
int n,K;
int tot;
void init(int cs){
for(int i=0;i<tot;i++){
for(int j=0;j<=K;j++)dp[cs][i][j]=Inf;
}
}
void calpre(int cs){
for(int i=0;i<tot;i++){
for(int j=0;j<=K;j++){
pre[cs][i][j]=dp[cs][i][j];
if(i)pre[cs][i][j]=min(pre[cs][i-1][j],pre[cs][i][j]);
}
}
}
inline void up(LL &x,LL y){if(x>y)x=y;}
void solve () {
V.clear();
LL tp=0;
V.push_back(tp);
for(int i=1;i<=n;i++){
scanf("%lld%lld",p+i,c+i);
for(int j=-n;j<=n;j++)if(p[i]+j>0)V.push_back(p[i]+j);
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
tot=V.size();
int cs=0;
init(cs);
dp[cs][0][0]=0;
calpre(cs);
for(int i=1;i<=n;i++){
init(cs^1);
//bubeikanjian
int tid=getid(p[i]);
for(int j=1;j<tot;j++){
LL cost=0;
if(j<tid){
cost=abs(V[j]-p[i])*c[i];
}
for(int k=0;k<=K;k++){
up(dp[cs^1][j][k],dp[cs][j][k]+cost);
}
}
//kanjian
for(int j=1;j<tot;j++){
LL cost=abs(V[j]-p[i])*c[i];
for(int k=1;k<=K;k++){
up(dp[cs^1][j][k],pre[cs][j-1][k-1]+cost);
up(dp[cs^1][j][k],pre[cs][j-1][k]+cost);
}
}
calpre(cs^1);
cs^=1;
}
LL ans=pre[cs][tot-1][K];
printf("%lld\n",ans);
} int main () {
while ( ~scanf ( "%d%d" , &n,&K ) ) solve () ;
return 0 ;
}
E. Perfect k-ary Tree
换根树形DP,需要记录树的高度,但是因为是满$k$叉树,因此树高是$O(\log n)$级别的。
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL;
const int mod=1e9+7,Maxn=100020;
int dp1[19][Maxn];
int n,K;
vector<int>G[Maxn];
int f[2][6];
inline void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void dfs1(int u,int p){
for(int i=0;i<G[u].size();i++){
int v=G[u][i];if(v==p)continue;
dfs1(v,u);
}
dp1[0][u]=1;
//printf("u=%d\n",u);
for(int i=1;(1<<i)<=n;i++){
int cs=0;
memset(f[cs],0,sizeof f[cs]);
f[cs][0]=1;
for(int j=0;j<G[u].size();j++){
int v=G[u][j];if(v==p)continue;
memset(f[cs^1],0,sizeof f[cs^1]);
for(int k=0;k<=K;k++){
if(!f[cs][k])continue;
if(k<K)up(f[cs^1][k+1],1LL*f[cs][k]*dp1[i-1][v]%mod);
up(f[cs^1][k],f[cs][k]);
}
cs^=1;
}
dp1[i][u]=f[cs][K];
}
//for(int i=0;(1<<i)<=n;i++)printf("%d ",dp1[i][u]);puts("");
}
int dp2[19][Maxn];
int pre[Maxn][6],suf[Maxn][6];
int ans;
void dfs2(int u,int p){
for(int h=1;(1<<h)<=n;h++){
//suanqianhouzhui
memset(pre[0],0,sizeof pre[0]);
pre[0][0]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];if(v==p){memcpy(pre[i+1],pre[i],sizeof pre[i]);continue;}
memset(pre[i+1],0,sizeof pre[i+1]);
for(int j=0;j<=K;j++){
up(pre[i+1][j],pre[i][j]);
if(j<K)up(pre[i+1][j+1],1LL*dp1[h-1][v]*pre[i][j]%mod);
}
}
int lst=G[u].size();
memset(suf[lst],0,sizeof suf[lst]);
suf[lst][1]=dp2[h-1][u];
suf[lst][0]=1;
for(int i=G[u].size()-1;i>=0;i--){
int v=G[u][i];if(v==p){memcpy(suf[i],suf[i+1],sizeof suf[i+1]);continue;}
memset(suf[i],0,sizeof suf[i]);
for(int j=0;j<=K;j++){
up(suf[i][j],suf[i+1][j]);
if(j<K)up(suf[i][j+1],1LL*dp1[h-1][v]*suf[i+1][j]%mod);
}
/*
if(h==2&&u==2){
printf("v=%d\n",v);
for(int j=0;j<=K;j++)printf("",suf);
}
*/
}
/*
if(u==2){
puts("haha");
for(int i=0;i<=G[u].size();i++){
for(int j=0;j<=K;j++)printf("%d ",suf[i][j]);puts("");
}
}
*/
for(int i=0;i<G[u].size();i++){
int v=G[u][i];if(v==p)continue;
dp2[h][v]=0;
for(int j=0;j<=K;j++){
up(dp2[h][v],1LL*pre[i][j]*suf[i+1][K-j]%mod);
}
}
/*
if(suf[0][K]){
printf("u=%d h=%d suf=%d\n",u,h,suf[0][K]);
}
*/
up(ans,suf[0][K]);
}
for(int i=0;i<G[u].size();i++){
int v=G[u][i];if(v==p)continue;
dp2[0][v]=1;
dfs2(v,u);
} }
void solve () {
for(int i=1;i<=n;i++)G[i].clear();
for(int i=1;i<n;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
ans=n;
dfs1(1,0);
dfs2(1,0);
printf("%d\n",ans);
} int main () {
while ( ~scanf ( "%d%d" , &n,&K ) ) solve () ;
return 0 ;
}
F. Playing with Numbers
枚举答案中2和3的幂次来自哪里即可。
#include <bits/stdc++.h>
using namespace std ; const int MAXN = 50005 ; int a[MAXN] , b[MAXN] ;
int prea[MAXN][2] , preb[MAXN][2] ;
int sufa[MAXN][2] , sufb[MAXN][2] ;
int n ; double getlog ( int x , int y ) {
return x * log ( 2.0 ) + y * log ( 3.0 ) ;
} void getlcm () {
int ansa = 0 , ansb = 0 ;
for ( int i = 1 ; i <= n ; ++ i ) {
int tmpa = min ( prea[i - 1][1] , sufa[i + 1][1] ) ;
int tmpb = min ( preb[i - 1][1] , sufb[i + 1][1] ) ;
tmpa = max ( tmpa , a[i] ) ;
tmpb = max ( tmpb , b[i] ) ;
if ( getlog ( tmpa , tmpb ) > getlog ( ansa , ansb ) ) {
ansa = tmpa ;
ansb = tmpb ;
}
}
printf ( "%d %d" , ansa , ansb ) ;
} void getgcd () {
int ansa = 1000 , ansb = 1000 ;
for ( int i = 1 ; i <= n ; ++ i ) {
int tmpa = max ( prea[i - 1][0] , sufa[i + 1][0] ) ;
int tmpb = max ( preb[i - 1][0] , sufb[i + 1][0] ) ;
tmpa = min ( tmpa , a[i] ) ;
tmpb = min ( tmpb , b[i] ) ;
if ( getlog ( tmpa , tmpb ) < getlog ( ansa , ansb ) ) {
ansa = tmpa ;
ansb = tmpb ;
}
}
printf ( "%d %d" , ansa , ansb ) ;
} void solve () {
for ( int i = 1 ; i <= n ; ++ i ) {
scanf ( "%d%d" , &a[i] , &b[i] ) ;
}
if ( n == 1 ) {
printf ( "%d %d %d %d\n" , a[1] , b[1] , a[1] , b[1] ) ;
return ;
}
if ( n == 2 ) {
if ( a[1] < a[2] ) swap ( a[1] , a[2] ) ;
if ( b[1] < b[2] ) swap ( b[1] , b[2] ) ;
printf ( "%d %d %d %d\n" , a[1] , b[1] , a[1] , b[1] ) ;
printf ( "%d %d %d %d\n" , a[2] , b[2] , a[2] , b[2] ) ;
return ;
}
prea[0][0] = preb[0][0] = 0 ;
prea[0][1] = preb[0][1] = 1000 ;
sufa[n + 1][0] = sufb[n + 1][0] = 0 ;
sufa[n + 1][1] = sufb[n + 1][1] = 1000 ;
for ( int i = 1 ; i <= n ; ++ i ) {
prea[i][0] = max ( prea[i - 1][0] , a[i] ) ;
preb[i][0] = max ( preb[i - 1][0] , b[i] ) ;
prea[i][1] = min ( prea[i - 1][1] , a[i] ) ;
preb[i][1] = min ( preb[i - 1][1] , b[i] ) ;
}
for ( int i = n ; i >= 1 ; -- i ) {
sufa[i][0] = max ( sufa[i + 1][0] , a[i] ) ;
sufb[i][0] = max ( sufb[i + 1][0] , b[i] ) ;
sufa[i][1] = min ( sufa[i + 1][1] , a[i] ) ;
sufb[i][1] = min ( sufb[i + 1][1] , b[i] ) ;
}
for ( int i = 0 ; i < n ; ++ i ) {
if ( i <= n - 3 ) {
printf ( "%d %d" , prea[n][0] , preb[n][0] ) ;
} else if ( i == n - 2 ) {
getlcm () ;
} else {
printf ( "%d %d" , prea[n][1] , preb[n][1] ) ;
}
printf ( " " ) ;
if ( i == 0 ) {
printf ( "%d %d" , prea[n][0] , preb[n][0] ) ;
} else if ( i == 1 ) {
getgcd () ;
} else {
printf ( "%d %d" , prea[n][1] , preb[n][1] ) ;
}
puts ( "" ) ;
}
} int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}
G. Scaffolding
留坑。
H. Slim Cut
枚举割中最大的边,那么大于它的边都要保留,得到若干个连通块,那么需要把这些连通块划分给$S$或者$T$,使得点数尽量均衡,01背包即可。
用并查集维护连通块,那么就变成了带增删物品的01背包,在线段树上分治同时用bitset加速即可。
时间复杂度$O(\frac{n^2\log n}{64})$。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
const int N=50010,M=140000,MAXE=3000000;
typedef bitset<7010>BS;
int n,m,i,j,x,y,f[N],size[N],id[N];
int pos,st[N],en[N],val[N],cnt;
double ans=1e9;
int gq[M],g[M],v[MAXE],nxt[MAXE],ed;
BS base;
struct E{
int x,y,w;
}e[N];
inline bool cmp(const E&a,const E&b){return a.w>b.w;}
int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
inline void add(int&x,int y){
v[++ed]=y;
nxt[ed]=x;
x=ed;
}
inline void addquery(int x){
add(gq[pos],x);
}
inline void merge(int x,int y){
x=F(x);
y=F(y);
if(x==y)return;
en[id[x]]=pos;
en[id[y]]=pos;
pos++;
cnt++;
st[cnt]=pos;
val[cnt]=size[x]+size[y];
size[y]+=size[x];
f[x]=y;
id[y]=cnt;
}
void change(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){
add(g[x],p);
return;
}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,d,p);
if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
}
void dfs(int x,int a,int b,BS dp,int cur){
for(int i=g[x];i;i=nxt[i])dp|=dp<<v[i],cur+=v[i];
if(a==b){
if(cur!=n)while(1);
int now=-1;
for(int i=n/2;i>=1;i--)if(dp[i]){
now=i;
break;
}
if(now<1)return;
for(int i=gq[a];i;i=nxt[i]){
ans=min(ans,1.0*v[i]/now);
}
return;
}
int mid=(a+b)>>1;
dfs(x<<1,a,mid,dp,cur);
dfs(x<<1|1,mid+1,b,dp,cur);
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
e[i].x++;e[i].y++;
}
sort(e+1,e+m+1,cmp);
for(i=1;i<=n;i++){
f[i]=i;size[i]=1;
id[i]=++cnt;
val[i]=1;
st[i]=1;
}
pos=1;
for(i=1;i<=m;i=j){
addquery(e[i].w);
for(j=i;j<=m&&e[i].w==e[j].w;j++){
merge(e[j].x,e[j].y);
}
}
for(i=1;i<=cnt;i++)if(!en[i])en[i]=pos;
for(i=1;i<=cnt;i++)change(1,1,pos,st[i],en[i],val[i]);
base[0]=1;
dfs(1,1,pos,base,0);
printf("%.10f",ans);
}
I. Special Tour
留坑。
J. Taboo
建立AC自动机,然后DP即可,发现环就返回无限解。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
const int inf=100000000;
int n,i,j,x;
char s[N];
int tot,son[N][2],ban[N],fail[N],q[N];
int f[N],vis[N],in[N];
void ins(){
scanf("%s",s);
int l=strlen(s);
int i,x=0,w;
for(i=0;i<l;i++){
w=s[i]-'0';
if(!son[x][w])son[x][w]=++tot;
x=son[x][w];
}
ban[x]=1;
}
void make(){
int h=1,t=0,i,j,x;
fail[0]=-1;
for(i=0;i<2;i++)if(son[0][i])q[++t]=son[0][i];
while(h<=t){
for(x=q[h++],i=0;i<2;i++)
if(son[x][i]){
fail[son[x][i]]=son[fail[x]][i];
q[++t]=son[x][i];
ban[son[x][i]]|=ban[fail[son[x][i]]];
}else{
son[x][i]=son[fail[x]][i];
}
}
}
int dp(int x){
if(in[x]){
puts("-1");
exit(0);
}
if(vis[x])return f[x];
in[x]=1;
vis[x]=1;
f[x]=-inf;
if(!ban[x]){
f[x]=0;
for(int i=0;i<2;i++){
f[x]=max(f[x],dp(son[x][i])+1);
}
}
in[x]=0;
// printf("dp[%d]=%d\n",x,f[x]);
return f[x];
}
int main(){
scanf("%d",&n);
while(n--)ins();
make();
dp(0);
//printf("ans=%d\n",f[0]);
for(x=0,i=1;i<=f[0];i++){
for(int j=0;j<2;j++){
if(f[son[x][j]]+1==f[x]){
x=son[x][j];
printf("%d",j);
break;
}
}
}
puts("");
return 0;
}
K. Team Up
将包含关系建树,同时将技能按dfs序重标号,那么每门课程都是一个区间。
考虑贪心,每次取出包含这个点的最小的区间即可。
用并查集维护每个点向上第一个还可以选人的节点即可。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1500010;
const int inf=100000000;
int n,m,p,i,j,x,size[N],g[N],G[N],v[N],nxt[N],ed,a[N],son[N];
int from[N],father[N];
int st[N],en[N],dfn;
int ans;
int cnt;
int f[N];
bool vis[N];
vector<int>fin[300010];
inline bool cmp(int x,int y){return size[x]>size[y];}//
inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}//
void dfs(int x){//
for(int i=son[x];i;i=nxt[i])dfs(v[i]);//
for(int i=g[x];i;i=nxt[i]){//
// printf("dfn %d\n",v[i]);
if(!vis[v[i]]){
from[++dfn]=x;//
vis[v[i]]=1;
}
}//
en[x]=dfn;//
}//
int ask(int x){//
if(!x)return 0;//
if(f[x]==x){//
if(G[x])return x;//
f[x]=father[x];//
}//
return f[x]=ask(f[x]);//
}//
void solve(){//
while(1){//
int now=1;//
while(1){//
//printf("->%d %d\n",now,from[now]);
x=ask(from[now]);//return a class
if(!x)return;//
//if(!G[x])while(1);
int y=v[G[x]];//
G[x]=nxt[G[x]];//
fin[ans+1].push_back(y);//
now=en[x]+1;//
if(now>n)break;//
}
ans++;
}
}
int main(){
scanf("%d%d%d",&n,&m,&p);//
for(i=1;i<=m;i++){//
scanf("%d",&size[i]);//
for(j=0;j<size[i];j++){//
scanf("%d",&x);//
add(g[i],x);//
}//
}//50W
for(i=1;i<=p;i++){//
scanf("%d",&x);//
add(G[x],i);//
}//30W
for(i=1;i<=m;i++)a[i]=i;//
sort(a+1,a+m+1,cmp);//
for(i=1;i<=m;i++){//
x=a[i];//
father[x]=from[v[g[x]]];//
for(j=g[x];j;j=nxt[j]){//
from[v[j]]=x;//
}//
}//
for(i=1;i<=n;i++)if(!from[i])return puts("0"),0;//
for(i=1;i<=m;i++)if(father[i])add(son[father[i]],i);//30W
for(i=1;i<=m;i++)if(!father[i])dfs(i);//
//if(dfn<n)while(1);
for(i=1;i<=m;i++)f[i]=i;//
//for(i=1;i<=m;i++)printf("%d\n",father[i]);
solve();//
printf("%d\n",ans);//
for(i=1;i<=ans;i++){//
int t=fin[i].size();//
printf("%d",t);//
for(int j=0;j<t;j++)printf(" %d",fin[i][j]);//
puts("");//
}//
return 0;//
}//
Asia Hong Kong Regional Contest 2016的更多相关文章
- 2019-2020 ICPC Asia Hong Kong Regional Contest
题解: https://files.cnblogs.com/files/clrs97/19HKEditorial-V1.zip Code:(Part) A. Axis of Symmetry #inc ...
- Asia Hong Kong Regional Contest 2019
A. Axis of Symmetry B. Binary Tree n 的奇偶性决定胜负. C. Constructing Ranches 路径上点权之和大于,极大值两倍,这是路径上点能拼出多边形的 ...
- 2019-2020 ICPC Asia Hong Kong Regional Contest J. Junior Mathematician 题解(数位dp)
题目链接 题目大意 要你在[l,r]中找到有多少个数满足\(x\equiv f(x)(mod\; m)\) \(f(x)=\sum_{i=1}^{k-1} \sum_{j=i+1}^{k}d(x,i) ...
- Hong Kong Regional Online Preliminary 2016 C. Classrooms
Classrooms 传送门 The new semester is about to begin, and finding classrooms for orientation activities ...
- [bfs,深度记录] East Central North America Regional Contest 2016 (ECNA 2016) D Lost in Translation
Problem D Lost in Translation The word is out that you’ve just finished writing a book entitled How ...
- Northwestern European Regional Contest 2016 NWERC ,F题Free Weights(优先队列+Map标记+模拟)
传送门: Vjudge:https://vjudge.net/problem/Gym-101170F CF: http://codeforces.com/gym/101170 The city of ...
- 回文自动机 + DFS --- The 2014 ACM-ICPC Asia Xi’an Regional Contest Problem G.The Problem to Slow Down You
The Problem to Slow Down You Problem's Link: http://acm.hust.edu.cn/vjudge/problem/viewProblem.actio ...
- 2013 Asia acm Hangzhou Regional Contest 杭州现场赛
B Stealing Harry Potter's Precious 题目大意:给定一个n*m的地图,某些点可以走,某些点可以走某些点不可以走,给定一个起点,又给出了k个点k<=4,要求从起点 ...
- 【GYM102091】2018-2019 ACM-ICPC, Asia Nakhon Pathom Regional Contest
A-Evolution Game 题目大意:有$n$个不同的野兽,定义第$i$ 个野兽有 $i$ 个眼睛和 $h[i]$ 个角,你可以任意从中选择一个野兽进行进化,每次进化角数量必须增加,而且进化后要 ...
随机推荐
- pdfbox加载pdf时遇到wrappedioexception报错处理方式
现在一个项目要对pdf做处理.由于其中一个pdf约为80M左右,用pdfbox读取pdf时遇到了wrappedioexception错误.监控得到说内存不足.于是请教项目经理.他告诉我在Open De ...
- [每日一记] Python报错 IndentationError: unexpected indent
IndentationError: unexpected indent 代码缩进出现错误 今天这个报错的原因是,早些时候的代码里Tab和空格混起来用了,,,[不是我...是编辑器的锅 不过我已经把Su ...
- Eclipse 各版本版本号代号对应一览表
版本号 代号 日期 Eclipse 3.1 IO [木卫一,伊奥] 2005 Eclipse 3.2 Callisto [木卫四,卡里斯托] 2006 Eclipse 3.3 Eruopa ...
- 将MongoDB服务加入随机启动
将MongoDB服务加入随机启动 vi /etc/rc.local 使用vi编辑器打开配置文件,并在其中加入下面一行代码 /usr/local/mongodb/bin/mongod -dbpath=/ ...
- 多预览小图焦点轮播插件lrtk
多预览小图焦点轮播插件lrtk // JavaScript Document $(document).ready(function(){ //$('#select_btn li:first').css ...
- swift 的枚举、结构体、类
一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...
- webservices接口 file "/axis2-web/listsingleservice.jsp" not found 问题解决
搞了半天 ,原来是services.xml 配置的某个或者某些service 在代码中不存才.扫描的时候找不到对应的service代码所以就会报错
- Xcode 快速开发 代码块
Xcode的代码片段(Code Snippets)创建自定义的代码片段,当你重用这些代码片段时,会给你带来很大的方便. 常用的: 1.strong:@property (nonatomic,stron ...
- StringBuffer与StringBuilder的简单理解
联系:两者都适用于字符串的操作,都可以随便对字符串的内容进行变更操作,都继承至AbstractStringBuilder. 区别:StringBuffer是线程安全的,方法都加了synchronize ...
- 在dll里malloc/new/cvCreate分配内存,在exe里free/Releases释放内存时会出错。
写了个程序,在DLL中用malloc分配了一块内存,但是在exe程序中释放,结果程序crash,原因就是:其原因可能是堆被损坏,这也说明 TestMySticker.exe 中或它所加载的任何 DLL ...