2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)

时间:2022-04-21 06:04:41

A. Arranging Hat

$f[i][j]$表示保证前$i$个数字有序,修改了$j$次时第$i$个数字的最小值。

时间复杂度$O(n^3m)$。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a )
typedef pair<int,int>pi;
char ten='9'+1;
int n,m;
string name[55];
string dp[55][88];
string dp2[88];
int prej[55][88];
string pe[55][88];
void up(string &x,string &y,int i,int j,int p){
if(x>y){
prej[i][j]=p;
x=y;
pe[i][j]=y;
}
}
void solve(){
for(int i=0;i<n;i++)cin>>name[i];
for(int i=0;i<=n;i++){
for(int j=0;j<=n+n;j++){
dp[i][j].assign(m,'9'+1);
}
}
dp[0][0].assign(m,'0');
for(int i=0;i<n;i++){
for(int j=0;j<=n+n;j++){
string ss=dp[i][j];
if(ss[0]==ten)continue;
for(int k=0;k<=n+n;k++)dp2[k].assign(m,ten);
int use=0;
string tmp=name[i];
for(int k=0;k<m;k++){
if(tmp[k]>ss[k]){
if(use+j<=n+n){
//up(dp[i+1][use+j],tmp,i+1,use+j,j);
dp2[use]=min(dp2[use],tmp);
}
}
if(ss[k]+1<='9'){
string tmp2=tmp;
tmp2[k]=ss[k]+1;
if(use+j+1<=n+n){
//up(dp[i+1][use+j+1],tmp2,i+1,use+j+1,j);
dp2[use+1]=min(dp2[use+1],tmp2);
}
}
if(tmp[k]!=ss[k])use++;
tmp[k]=ss[k];
}
if(use+j<=n+n){
dp2[use]=min(dp2[use],tmp);
//up(dp[i+1][use+j],tmp,i+1,use+j,j);
}
for(int k=0;k<n+n;k++){
if(dp2[k][0]>'9')continue;
//if(i==2&&j==2)printf("k=%d\n",k);
int loc=-1;
for(int p=0;p<m;p++){
if(dp2[k][p]>ss[p]){loc=p;break;}
}
if(loc<0)continue;
//if(i==0&&k==0)printf("loc=%d\n",loc);
if(ss[loc]+1<dp2[k][loc]){
string nxt=dp2[k];
nxt[loc]=ss[loc]+1;
dp2[k+1]=min(dp2[k+1],nxt);
//up(dp2[k+1],nxt,i+1,k+1,j);
}
loc++;
string nxt=dp2[k];
while(loc<m&&nxt[loc]=='0')loc++;
if(loc<m){
nxt[loc]='0';
dp2[k+1]=min(dp2[k+1],nxt);
//up(dp[i+1][k+1],nxt,i+1,k+1,j);
}
}
for(int k=0;k+j<=n+n;k++){
up(dp[i+1][k+j],dp2[k],i+1,k+j,j);
}
}
}
/*
for(int i=0;i<n;i++){
for(int j=0;j<=n+n;j++){
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
*/
int ans=-1;
for(int i=0;i<=n+n;i++){
if(dp[n][i][0]<='9'){
ans=i;
break;
}
}
vector<string>res;
for(int i=n,j=ans;i;i--){
res.push_back(pe[i][j]);
//printf("i=%d j=%d\n",i,j);
j=prej[i][j];
}
reverse(res.begin(),res.end());
//printf("%d\n",ans);
for(int i=0;i<res.size();i++)cout<<res[i]<<endl;
}
int main () {
//scanf ( "%d%d" , &n,&m ) ;
cin>>n>>m;solve () ;
int a,b,casdasd,d;
return 0 ;
}

  

B. British Menu

首先求出SCC,缩点之后对于每个SCC枚举起点爆搜,当搜到其它SCC时换成DP即可。

时间复杂度$O(5!(n+m))$。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int>P;
const int N=100010,M=3000010;
int n,m,i,j,x,y,g[N],G[N],sg[N],v[M],nxt[M],ed,d[N];
int ans,dp[N],rk[N];
P e[1000010];
bool vis[N];
int h,t,q[N],from[N],cnt,pool[N];
vector<int>son[N];
inline void add(int x,int y){
// printf("add %d %d\n",x,y);
v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
v[++ed]=x;nxt[ed]=G[y];G[y]=ed;
}
inline void ADD(int x,int y){
if(x==y)return;
//printf("ADD %d %d\n",x,y);
d[y]++;
v[++ed]=y;nxt[ed]=sg[x];sg[x]=ed;
}
void dfs(int x){
vis[x]=1;
for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])dfs(v[i]);
q[++t]=x;
}
void dfs2(int x,int y){
vis[x]=0;
from[x]=y;
//pool[++cnt]=x;
//rk[x]=cnt;
son[y].push_back(x);
for(int i=G[x];i;i=nxt[i])if(vis[v[i]])dfs2(v[i],y);
}
void dfs3(int x,int y,int S){
// printf("%d %d %d\n",x,y,S);
ans=max(ans,y);
for(int i=g[x];i;i=nxt[i]){
int u=v[i];
if(from[x]!=from[u])dp[u]=max(dp[u],y+1);
else{
if(S>>rk[u]&1)continue;
dfs3(u,y+1,S|(1<<rk[u]));
}
}
}
inline void deal(int o){//calc SCC o
//printf("deal %d\n",o);
cnt=0;
for(vector<int>::iterator it=son[o].begin();it!=son[o].end();it++){
pool[++cnt]=*it;
rk[*it]=cnt;
}
for(int i=1;i<=cnt;i++){
dfs3(pool[i],dp[pool[i]],1<<i);
}
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
e[i]=P(x,y);
}
sort(e+1,e+m+1);
for(i=1;i<=m;i++)if(e[i]!=e[i-1])add(e[i].first,e[i].second);
for(i=1;i<=n;i++)if(!vis[i])dfs(i);
for(i=n;i;i--)if(vis[q[i]]){
//cnt=0;
dfs2(q[i],q[i]);
//for(j=1;j<=cnt;j++)dfs3(pool[j],)
}
for(i=1;i<=n;i++)for(j=g[i];j;j=nxt[j])ADD(from[i],from[v[j]]);
for(h=1,t=0,i=1;i<=n;i++)if(from[i]==i&&!d[i]){
q[++t]=i;
// printf("start %d\n",i);
}
while(h<=t)for(i=sg[q[h++]];i;i=nxt[i]){
if(!(--d[v[i]])){
q[++t]=v[i];
// printf("push %d %d\n",q[h-1],v[i]);
}
}
for(i=1;i<=t;i++){
deal(q[i]);
}
printf("%d",ans+1);
}

  

C. Careful Ascent

推公式。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100 ; int x , y , n ; void solve () {
scanf ( "%d" , &n ) ;
double v = 0 , f ;
for ( int i = 1 ; i <= n ; ++ i ) {
int l , r ;
scanf ( "%d%d%lf" , &l , &r , &f ) ;
y -= r - l ;
v += ( r - l ) * f ;
}
v += y ;
printf ( "%.10f\n" , x / v ) ;
} int main () {
while ( ~scanf ( "%d%d" , &x , &y ) ) solve () ;
return 0 ;
}

  

D. Driving in Optimistan

留坑。

E. Exam Redistribution

从大到小发试卷即可。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a )
typedef pair<int,int>pi;
int n;
int a[20000];
void solve () {
vector<pi>V;
for(int i=1;i<=n;i++)scanf("%d",a+i),V.push_back(pi(a[i],i));
sort(V.begin(),V.end(),greater<pi>());
int sum=0;
for(int i=1;i<V.size();i++)sum+=V[i].first;
if(sum<V[0].first)puts("impossible");
else{
for(int i=0;i<n;i++)printf("%d%c",V[i].second,i==n-1?'\n':' ');
}
} int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
}

  

F. Free Weights

二分答案,然后括号匹配即可。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a )
typedef pair<int,int>pi;
const int Maxn=1000020;
int n;
int a[2][Maxn];
int sta[Maxn];
int top;
bool check(int mid){
int cnt=0;
for(int i=0;i<2;i++){
top=0;
for(int j=1;j<=n;j++){
if(a[i][j]<=mid)continue;
if(top&&sta[top]!=a[i][j])return 0;
if(top&&sta[top]==a[i][j]){
cnt++;
top--;
continue;
}
sta[++top]=a[i][j];
}
if(top)return 0;
}
return 1;
}
void solve () {
for(int it=0;it<2;it++)
for(int i=1;i<=n;i++)scanf("%d",&a[it][i]);
int l=-1,r=1e9+7;
while(l+1<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid;
}
printf("%d\n",r);
} int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}

  

G. Gotta Nudge 'Em All

每条链的答案独立,枚举双倍经验结束的时刻,每次插入新的怪物时,二分那条链上所有怪物进化到了哪一层,树状数组维护判定。

时间复杂度$O(n\log^2n)$。

H. Hamiltonian Hypercube

格雷码转二进制。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100 ; int n ;
int pre[MAXN] , now[MAXN] ; LL get ( int n ) {
LL x = 0 ;
for ( int i = n - 1 ; i >= 0 ; -- i ) {
scanf ( "%1d" , &pre[i] ) ;
}
now[n - 1] = pre[n - 1] ;
for ( int i = n - 2 ; i >= 0 ; -- i ) {
now[i] = now[i + 1] ^ pre[i] ;
}
for ( int i = 0 ; i < n ; ++ i ) if ( now[i]) x += 1LL << i ;
return x ;
} void solve () {
LL x = get ( n ) , y = get ( n ) ;
printf ( "%lld\n" , y - x - 1 ) ;
} int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}

  

I. Iron and Coal

BFS求出起点到每个点、每个点到两种关键点的最短路,然后枚举分界点即可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010,M=2000010;
int n,c0,c1,i,j,x,is0[N],is1[N],g[N],G[N],v[M],nxt[M],ed,ans=M,h,t,q[N];
int A[N],B[N],C[N];
inline void add(int x,int y){
v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
v[++ed]=x;nxt[ed]=G[y];G[y]=ed;
}
int main(){
scanf("%d%d%d",&n,&c0,&c1);
while(c0--)scanf("%d",&x),is0[x]=1;
while(c1--)scanf("%d",&x),is1[x]=1;
for(i=1;i<=n;i++){
scanf("%d",&j);
while(j--){
scanf("%d",&x);
add(i,x);
}
}
for(i=1;i<=n;i++)A[i]=M;
A[q[h=t=1]=1]=0;
while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(A[x]+1<A[v[i]])A[q[++t]=v[i]]=A[x]+1;
for(i=1;i<=n;i++)B[i]=M;
h=1,t=0;
for(i=1;i<=n;i++)if(is0[i])B[q[++t]=i]=0;
while(h<=t)for(i=G[x=q[h++]];i;i=nxt[i])if(B[x]+1<B[v[i]])B[q[++t]=v[i]]=B[x]+1;
for(i=1;i<=n;i++)C[i]=M;
h=1,t=0;
for(i=1;i<=n;i++)if(is1[i])C[q[++t]=i]=0;
while(h<=t)for(i=G[x=q[h++]];i;i=nxt[i])if(C[x]+1<C[v[i]])C[q[++t]=v[i]]=C[x]+1;
for(i=1;i<=n;i++)ans=min(ans,A[i]+B[i]+C[i]);
if(ans>n)puts("impossible");else printf("%d",ans);
}

  

J. Jupiter Orbiter

网络流。

#include <bits/stdc++.h>
using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 3005 ;
const int MAXE = 100005 ;
const int INF = 0x3f3f3f3f ; struct Edge {
int v , c , n ;
Edge () {}
Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}
} ; Edge E[MAXE] ;
int H[MAXN] , cntE ;
int d[MAXN] , cur[MAXN] , pre[MAXN] , gap[MAXN] ;
int Q[MAXN] , head , tail ;
int s , t , nv , flow ; int n , m , q , cnt ;
int idx[35][35][2] ;
int qi[MAXN] , ci[MAXN] , cost[MAXN] ; void init () {
cntE = 0 ;
clr ( H , -1 ) ;
} void addedge ( int u , int v , int c ) {
E[cntE] = Edge ( v , c , H[u] ) ;
H[u] = cntE ++ ;
E[cntE] = Edge ( u , 0 , H[v] ) ;
H[v] = cntE ++ ;
} void rev_bfs () {
head = tail = 0 ;
clr ( d , -1 ) ;
clr ( gap , 0 ) ;
gap[0] = 1 ;
d[t] = 0 ;
Q[tail ++] = t ;
while ( head != tail ) {
int u = Q[head ++] ;
for ( int i = H[u] ; ~i ; i = E[i].n ) {
int v = E[i].v ;
if ( d[v] == -1 ) {
Q[tail ++] = v ;
d[v] = d[u] + 1 ;
gap[d[v]] ++ ;
}
}
}
} int isap () {
memcpy ( cur , H , sizeof cur ) ;
rev_bfs () ;
int u = pre[s] = s , f = flow = 0 , i , mi ;
while ( d[s] < nv ) {
if ( u == t ) {
for ( f = INF , i = s ; i != t ; i = E[cur[i]].v ) {
if ( f > E[cur[i]].c ) f = E[cur[u = i]].c ;
}
for ( i = s ; i != t ; i = E[cur[i]].v ) {
E[cur[i]].c -= f ;
E[cur[i] ^ 1].c += f ;
}
flow += f ;
}
for ( i = cur[u] ; ~i ; i = E[i].n ) {
if ( E[i].c && d[u] == d[E[i].v] + 1 ) break ;
}
if ( ~i ) {
cur[u] = i ;
pre[E[i].v] = u ;
u = E[i].v ;
} else {
if ( 0 == -- gap[d[u]] ) break ;
for ( mi = nv , i = H[u] ; ~i ; i = E[i].n ) {
int v = E[i].v ;
if ( E[i].c && mi > d[v] ) {
cur[u] = i ;
mi = d[v] ;
}
}
d[u] = mi + 1 ;
gap[d[u]] ++ ;
u = pre[u] ;
}
}
return flow ;
} void solve () {
init () ;
for ( int i = 1 ; i <= m ; ++ i ) {
scanf ( "%d" , &qi[i] ) ;
}
for ( int i = 1 ; i <= q ; ++ i ) {
scanf ( "%d" , &ci[i] ) ;
}
s = cnt = 0 ;
for ( int i = 1 ; i <= n ; ++ i ) {
for ( int j = 1 ; j <= q ; ++ j ) {
idx[i][j][0] = ++ cnt ;
idx[i][j][1] = ++ cnt ;
}
}
t = cnt + n + 1 ;
nv = t + 1 ;
LL tot = 0 ;
for ( int i = 1 ; i <= n ; ++ i ) {
int x , y ;
scanf ( "%d" , &x ) ;
for ( int j = 1 ; j <= q ; ++ j ) {
cost[j] = 0 ;
}
for ( int j = 1 ; j <= m ; ++ j ) {
scanf ( "%d" , &y ) ;
cost[qi[j]] += y ;
tot += y ;
}
++ cnt ;
for ( int j = 1 ; j <= q ; ++ j ) {
addedge ( s , idx[i][j][0] , cost[j] ) ;
addedge ( idx[i][j][0] , idx[i][j][1] , ci[j] ) ;
addedge ( idx[i][j][1] , cnt , INF ) ;
if ( i < n ) addedge ( idx[i][j][1] , idx[i + 1][j][0] , ci[j] ) ;
}
addedge ( cnt , t , x ) ;
}
isap () ;
if ( flow != tot ) printf ( "im" ) ;
printf ( "possible\n" ) ;
} int main () {
while ( ~scanf ( "%d%d%d" , &n , &q , &m ) ) solve () ;
return 0 ;
}

  

K. Kiwi Trees

由于边长以及角度的限制,每个凸角必能卡住一个圆,然后$O(n^2)$枚举所有可能的圆对即可。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const double eps=1e-8;
const int N=10000;
int sgn(double x){
if(x<-eps)return -1;
if(x>eps)return 1;
return 0;
}
struct vec{
double x,y;
vec(){x=y=0;}
vec(double _x,double _y){x=_x,y=_y;}
vec operator+(vec v){return vec(x+v.x,y+v.y);}
vec operator-(vec v){return vec(x-v.x,y-v.y);}
vec operator*(double v){return vec(x*v,y*v);}
vec operator/(double v){return vec(x/v,y/v);}
double operator*(vec v){return x*v.x+y*v.y;}
double len(){return hypot(x,y);}
vec trunc(double l){return (*this)*l/len();}
}a[N],q[N];
int n,m,i,j;
double cross(vec a,vec b){return a.x*b.y-a.y*b.x;}
double dist_point_to_line(vec p,vec a,vec b){
return fabs(cross(p-a,b-a))/(b-a).len();
}
double dist_point_to_segment(vec p,vec a,vec 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());
}
void solve(vec A,vec B,vec C){
if(cross(A-B,C-B)<0)return;
vec D=A-B;
D=D/D.len();
D=D+B;
vec E=C-B;
E=E/E.len();
E=E+B;
vec F=(D+E)/2.0;
F=F-B;
F=F/F.len();
double l=0,r=1e8,mid;
while(l+eps<r){
mid=(l+r)/2.0;
if(dist_point_to_line(B+(F*mid),A,B)<4000.1)l=mid;else r=mid;
}
vec o=B+(F*l);
for(int i=0;i<n;i++){
if(sgn(dist_point_to_segment(o,a[i],a[i+1])-4000.0)<=0)return;
}
q[++m]=o;
}
inline bool check(vec a,vec b){return sgn((a-b).len()-8000.1)>=0;}
int main(){
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%lf%lf",&a[i].x,&a[i].y);//mm radius=4000mm
a[i+n]=a[i];
}
for(i=0;i<n;i++)solve(a[i],a[i+1],a[i+2]);
for(i=1;i<=m;i++)for(j=1;j<i;j++)if(check(q[i],q[j])){
printf("%.8f %.8f\n",q[i].x,q[i].y);
printf("%.8f %.8f\n",q[j].x,q[j].y);
return 0;
}
puts("impossible");
}