A. Within Arm's Reach
留坑。
B. Bribing Eve
枚举经过$1$号点的所有直线,统计直线右侧的点数,旋转卡壳即可。
时间复杂度$O(nlog n)$。
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=2000010; const double eps=1e-7; int _,n,i,x,y,at_center,X,Y,j,m,inarea,online,ansmin,ansmax; struct P{ int x,y,z; double o; P(){} P(int _x,int _y,int _z){ x=_x,y=_y; z=_z; o=atan2(y,x); } }a[N],b[N]; int s[N]; inline bool cmp(const P&a,const P&b){return a.o<b.o;} inline int cross(const P&a,const P&b){ return a.x*b.y-a.y*b.x; } int main(){ scanf("%d",&_); scanf("%d%d",&X,&Y); _--; while(_--){ scanf("%d%d",&x,&y); if(x==X&&y==Y){at_center++;continue;} a[++n]=P(x-X,y-Y,1); a[++n]=P(X-x,Y-y,0); } if(!n){ printf("%d %d",1,at_center+1); return 0; } sort(a+1,a+n+1,cmp); for(i=1;i<=n;i=j){ int sum=0; for(j=i;j<=n&&a[i].x*a[j].y==a[j].x*a[i].y&&fabs(a[i].o-a[j].o)<eps;j++)sum+=a[j].z; b[++m]=P(a[i].x,a[i].y,sum); } for(i=1;i<=m;i++)b[i+m]=b[i]; for(i=1;i<=m+m;i++)s[i]=s[i-1]+b[i].z; ansmin=N; ansmax=0; for(i=j=1;i<=m;i++){ if(j<i)j=i; while(j+1<i+m&&cross(b[i],b[j+1])>=0)j++; //printf("%d %d %d ",b[i].x,b[i].y,b[i].z); if(b[i].x<0||b[i].y>0)continue; inarea=s[j]-s[i-1]; online=b[i].z; if(i<j&&cross(b[i],b[j])==0)online+=b[j].z; inarea-=online; online+=at_center; //printf("%d %d %d %d %d %d ",inarea,online,b[i].x,b[i].y,b[j].x,b[j].y); ansmin=min(ansmin,inarea+1); ansmax=max(ansmax,inarea+online+1); } printf("%d %d",ansmin,ansmax); }
C. Candle Box
模拟。
#include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<time.h> #include<assert.h> #include<iostream> using namespace std; typedef long long LL; typedef pair<int,int>pi; const int Inf=2e9; int d,n,m; int ans; int cal1(int x){ if(x<4)return 0; return (1+x)*x/2-6; } int cal2(int x){ if(x<3)return 0; return (1+x)*x/2-3; } bool check(int x,int y){ if(x<0||y<0)return 0; int ned1=cal1(x),ned2=cal2(y); if(ned1>n)return 0; if(n+m==ned1+ned2){ ans=min(ans,n-ned1); } return 1; /* for(int i=0;i<=t2;i++){ if(t1+i==n&&t2-i==m){ ans=min(ans,i); } } */ /* for(int i=0;i<=t2-1;i++){ if(t1+i==n&&t2-1-i==m){ ans=min(ans,i); } } for(int i=0;i<=t2+1;i++){ if(t1+i==n&&t2+1-i==m){ ans=min(ans,i); } } */ return 0; } int main(){ while(scanf("%d%d%d",&d,&n,&m)!=EOF){ bool flag=1; ans=Inf; for(int i=d;i<=1020;i++){ check(i,i-d); } if(ans==Inf)while(1); printf("%d ",ans); } return 0; }
D. Dinner Bet
$f[i][j][k]$表示有$i$个仅属于第一个人的数字被选中,$j$个仅属于第二个人的数字被选中,$k$个属于两个人的数字被选中的期望次数。
#include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include<set> #include<map> #include<queue> #include<time.h> #include<assert.h> #include<iostream> using namespace std; typedef long long LL; typedef pair<int,int>pi; int n,d,ned; int idx[55]; int cnt[3]; double dp[12][12][12]; LL C[100][100]; double dfs(int a0,int a1,int a2){ double &t=dp[a0][a1][a2]; if(t>-0.5)return t; if(a0+a2>=ned||a1+a2>=ned)return t=0; double tmp=1; double nedp; for(int ad0=0;ad0+a0<=cnt[0];ad0++) for(int ad1=0;ad1+a1<=cnt[1];ad1++) for(int ad2=0;ad2+a2<=cnt[2];ad2++){ if(ad0+ad1+ad2>d)continue; double p=( C[n-(cnt[0]-a0)-(cnt[1]-a1)-(cnt[2]-a2)][d-ad0-ad1-ad2]* C[(cnt[0]-a0)][ad0]* C[(cnt[1]-a1)][ad1]* C[(cnt[2]-a2)][ad2]+0.0)/C[n][d]; if(!ad0&&!ad1&&!ad2)nedp=p; else{ dfs(a0+ad0,a1+ad1,a2+ad2); tmp+=p*dp[a0+ad0][a1+ad1][a2+ad2]; } } t=tmp/(1-nedp); // printf("a0=%d a1=%d a2=%d dp=%.2f ned=%d ",a0,a1,a2,t,ned); return t; } int main(){ for(int i=0;i<=50;i++)C[i][0]=1; for(int i=1;i<=50;i++){ for(int j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j]; } while(scanf("%d%d%d",&n,&d,&ned)!=EOF){ memset(idx,0,sizeof idx); memset(cnt,0,sizeof cnt); for(int i=0;i<2;i++){ for(int j=0;j<ned;j++){ int x;scanf("%d",&x); idx[x]|=1<<i; } } for(int i=1;i<=n;i++)if(idx[i])cnt[idx[i]-1]++; memset(dp,-1,sizeof dp); dfs(0,0,0); printf("%.12f ",dp[0][0][0]); } return 0; }
E. Passwords
建立AC自动机,$f[i][j][x][y][z]$表示串长为$i$,目前走到了$j$这个点,小写字母/大写字母/数字是否出现的方案数。
#include<cstdio> #include<cstring> const int N=1010,P=1000003; int A,B,tot,son[N][26],fail[N],q[N],ban[N],ans,i,j,x,y,z,t,o; int n;char s[N]; int f[22][N][2][2][2];//lower upper digit inline void up(int&x,int y){ x+=y; if(x>=P)x-=P; } void insert(){ scanf("%s",s); for(int l=strlen(s),x=0,i=0,w;i<l;i++){ if(!son[x][w=s[i]-'a'])son[x][w]=++tot;x=son[x][w]; if(i==l-1)ban[x]=1; } } void make(){ int h=1,t=0,i,j,x;fail[0]=-1; for(i=0;i<26;i++)if(son[0][i])q[++t]=son[0][i]; while(h<=t)for(x=q[h++],i=0;i<26;i++) if(son[x][i]){ ban[son[x][i]]|=ban[fail[son[x][i]]=son[fail[x]][i]]; q[++t]=son[x][i]; }else son[x][i]=son[fail[x]][i]; } int main(){ scanf("%d%d%d",&A,&B,&n); while(n--)insert(); make(); f[0][0][0][0][0]=1; for(i=0;i<B;i++)for(j=0;j<=tot;j++)for(x=0;x<2;x++)for(y=0;y<2;y++)for(z=0;z<2;z++){ if(!f[i][j][x][y][z])continue; for(t=0;t<26;t++){ o=son[j][t]; if(ban[o])continue; up(f[i+1][o][1][y][z],f[i][j][x][y][z]);//lower up(f[i+1][o][x][1][z],f[i][j][x][y][z]);//upper } for(t=0;t<10;t++){ o=0; if(t==0)o=son[j]['o'-'a']; if(t==1)o=son[j]['i'-'a']; if(t==3)o=son[j]['e'-'a']; if(t==5)o=son[j]['s'-'a']; if(t==7)o=son[j]['t'-'a']; if(ban[o])continue; up(f[i+1][o][x][y][1],f[i][j][x][y][z]);//digit } } for(i=A;i<=B;i++)for(j=0;j<=tot;j++)up(ans,f[i][j][1][1][1]); printf("%d",ans); }
F. Performance Review
按权值排序之后树状数组维护dfs序即可。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=100010; int n,i,x,a[N],b[N],q[N],g[N],nxt[N],root,j,st[N],en[N],dfn; int flag[N]; ll bit[N],ans[N]; inline bool cmp(int x,int y){return a[x]<a[y];} inline void add(int x,int y){flag[y]=1;nxt[y]=g[x];g[x]=y;} void dfs(int x){ st[x]=++dfn; for(int i=g[x];i;i=nxt[i])dfs(i); en[x]=dfn; } inline void modify(int x,int p){for(;x<=n;x+=x&-x)bit[x]+=p;} inline ll ask(int x){ll t=0;for(;x;x-=x&-x)t+=bit[x];return t;} int main(){ scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d%d%d",&x,&a[i],&b[i]); if(x>0)add(x,i);else root=i; } for(i=1;i<=n;i++)if(!flag[i])dfs(i); for(i=1;i<=n;i++)q[i]=i; sort(q+1,q+n+1,cmp); for(i=1;i<=n;i=j){ for(j=i;j<=n&&a[q[i]]==a[q[j]];j++)ans[q[j]]=ask(en[q[j]])-ask(st[q[j]]-1); for(j=i;j<=n&&a[q[i]]==a[q[j]];j++)modify(st[q[j]],b[q[j]]); } for(i=1;i<=n;i++)printf("%I64d ",ans[i]); }
G. Cairo Corridor
找出与四个边界都连通的连通块,然后枚举连通块里每个点,如果它不是割点,且去掉它之后剩余部分依旧与四个边界都连通,则无解。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 300005 ; const int mod = 13 ; const int INF = 0x3f3f3f3f ; struct Node { int x , y , v ; Node () {} Node ( int x , int y , int v ) : x ( x ) , y ( y ) , v ( v ) {} } ; vector < int > G[MAXN] , now ; int dfn[MAXN] , low[MAXN] , dfs_clock ; int cut[MAXN] ; int vis[MAXN] ; int S[MAXN] , top ; int a[255][255] , b[255][255] ; int idx[255][255][2] , cnt ; Node is[MAXN] ; int num[4] ;//l r u d int p[MAXN] ; int n , m ; void tarjan ( int u , int pre ) { int v ; low[u] = dfn[u] = ++ dfs_clock ; S[top ++] = u ; int son = 0 , pre_cnt = 0 ; for ( int i = 0 ; i < G[u].size () ; ++ i ) { v = G[u][i] ; if ( v == pre && pre_cnt == 0 ) { pre_cnt ++ ; continue ; } if ( !dfn[v] ) { ++ son ; tarjan ( v , u ) ; if ( low[u] > low[v] ) low[u] = low[v] ; if ( u != pre && low[v] >= dfn[u] ) cut[u] = 1 ; } else low[u] = min ( low[u] , dfn[v] ) ; } if ( u == pre && son > 1 ) cut[u] = 1 ; -- top ; } int F ( int x ) { return p[x] == x ? x : ( p[x] = F ( p[x] ) ) ; } void add ( int x , int y ) { if ( is[x].v ) { if ( b[is[x].x][is[x].y] ) return ; } else { if ( a[is[x].x][is[x].y] ) return ; } if ( is[y].v ) { if ( b[is[y].x][is[y].y] ) return ; } else { if ( a[is[y].x][is[y].y] ) return ; } p[F ( x )] = F ( y ) ; G[x].push_back ( y ) ; } void dfs ( int u , int f ) { vis[u] = 1 ; now.push_back ( u ) ; for ( int i = 0 ; i < G[u].size () ; ++ i ) { int v = G[u][i] ; if ( v == f ) continue ; if ( vis[v] ) continue ; dfs ( v , u ) ; } } int addval ( int x , int y , int v , int f ) { if ( ( x + y ) % 2 == 0 ) { if ( v == 0 && y == 1 ) num[0] += f ; if ( v == 1 && y == m ) num[1] += f ; if ( x == 1 ) num[2] += f ; if ( x == n ) num[3] += f ; } else { if ( y == 1 ) num[0] += f ; if ( y == m ) num[1] += f ; if ( v == 0 && x == 1 ) num[2] += f ; if ( v == 1 && x == n ) num[3] += f ; } } int can_del ( int o ) { int x = is[o].x , y = is[o].y , v = is[o].v , ok = 1 ; addval ( x , y , v , -1 ) ; if ( !num[0] || !num[1] || !num[2] || !num[3] ) ok = 0 ; addval ( x , y , v , 1 ) ; return ok ; } void solve () { cnt = 0 ; scanf ( "%d%d" , &n , &m ) ; for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 1 ; j <= m ; ++ j ) { scanf ( "%1d%1d" , &a[i][j] , &b[i][j] ) ; idx[i][j][0] = ++ cnt ; is[cnt] = Node ( i , j , 0 ) ; idx[i][j][1] = ++ cnt ; is[cnt] = Node ( i , j , 1 ) ; } } for ( int i = 1 ; i <= cnt ; ++ i ) { G[i].clear () ; } for ( int i = 1 ; i <= cnt ; ++ i ) { p[i] = i ; } for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 1 ; j <= m ; ++ j ) { add ( idx[i][j][0] , idx[i][j][1] ) ; add ( idx[i][j][1] , idx[i][j][0] ) ; if ( ( i + j ) % 2 == 0 ) { if ( i < n ) add ( idx[i][j][0] , idx[i + 1][j][0] ) ; if ( i > 1 ) add ( idx[i][j][0] , idx[i - 1][j][1] ) ; if ( j > 1 ) add ( idx[i][j][0] , idx[i][j - 1][0] ) ; if ( j > 1 ) add ( idx[i][j][0] , idx[i][j - 1][1] ) ; if ( i < n ) add ( idx[i][j][1] , idx[i + 1][j][0] ) ; if ( i > 1 ) add ( idx[i][j][1] , idx[i - 1][j][1] ) ; if ( j < m ) add ( idx[i][j][1] , idx[i][j + 1][0] ) ; if ( j < m ) add ( idx[i][j][1] , idx[i][j + 1][1] ) ; } else { if ( j < m ) add ( idx[i][j][0] , idx[i][j + 1][0] ) ; if ( j > 1 ) add ( idx[i][j][0] , idx[i][j - 1][1] ) ; if ( i > 1 ) add ( idx[i][j][0] , idx[i - 1][j][0] ) ; if ( i > 1 ) add ( idx[i][j][0] , idx[i - 1][j][1] ) ; if ( j < m ) add ( idx[i][j][1] , idx[i][j + 1][0] ) ; if ( j > 1 ) add ( idx[i][j][1] , idx[i][j - 1][1] ) ; if ( i < n ) add ( idx[i][j][1] , idx[i + 1][j][0] ) ; if ( i < n ) add ( idx[i][j][1] , idx[i + 1][j][1] ) ; } } } clr ( dfn , 0 ) ; clr ( low , 0 ) ; clr ( cut , 0 ) ; top = dfs_clock = 0 ; for ( int i = 1 ; i <= cnt ; ++ i ) if ( !dfn[i] ) { tarjan ( i , i ) ; } int ans = -1 ; clr ( vis , 0 ) ; for ( int i = 1 ; i <= cnt ; ++ i ) if ( F ( i ) == i ) { if ( is[i].v ) { if ( b[is[i].x][is[i].y] ) continue ; } else { if ( a[is[i].x][is[i].y] ) continue ; } now.clear () ; clr ( num , 0 ) ; dfs ( i , i ) ; for ( int j = 0 ; j < now.size () ; ++ j ) { int x = is[now[j]].x , y = is[now[j]].y , v = is[now[j]].v ; addval ( x , y , v , 1 ) ; } if ( !num[0] || !num[1] || !num[2] || !num[3] ) continue ; int ok = 1 ; for ( int j = 0 ; j < now.size () ; ++ j ) { if ( !cut[now[j]] ) { if ( can_del ( now[j] ) ) { ok = 0 ; //break ; } } } if ( ok ) ans = max ( ans , ( int ) now.size () ) ; } if ( ans == -1 ) printf ( "NO MINIMAL CORRIDOR " ) ; else printf ( "%d " , ans ) ; } int main () { int T = 0 ; scanf ( "%d" , &T ) ; for ( int i = 1 ; i <= T ; ++ i ) { //printf ( "Case #%d: " , i ) ; solve () ; } if ( T ) return 0 ; //while ( ~scanf ( "%d%d%d%d" , &n , &s , &t , &m ) ) solve () ; return 0 ; }
H. Pascal's Hyper-Pyramids
等价于找$D$个非负整数$x_1,x_2,...,x_D$,且和为$H-1$,答案为$frac{(H-1)!}{x_1!x_2!...x_D!}$。
考虑爆搜,加上$x_ileq x_{i+1}$以及可行性剪枝即可,计算答案可以分解质因数。
#include<cstdio> #include<set> using namespace std; typedef unsigned long long ll; const int N=35; int n,m,i,j; int p[N],v[N],tot; int f[N][N],g[N],q[N]; ll po[N][N]; set<ll>T; void divide(int n){ int t=n; for(int i=0;i<tot;i++)while(t%p[i]==0)f[n][i]++,t/=p[i]; } void cal(){ for(int i=0;i<tot;i++)g[i]=f[m][i]; for(int i=0;i<n;i++)for(int j=0;j<tot;j++)g[j]-=f[q[i]][j]; ll ret=1; for(int i=0;i<tot;i++)ret*=po[i][g[i]]; T.insert(ret); } void dfs(int x,int y,int z){//now consider x,0<=x<=y,sum=z if((n-x)*y+z<m)return; if(x==n){ if(z==m){ cal(); } return; } for(int i=0;i<=y;i++){ if(z+i>m)return; q[x]=i; dfs(x+1,i,z+i); } } int main(){ for(i=2;i<N;i++)if(!v[i]){ p[tot++]=i; for(j=i+i;j<N;j+=i)v[j]=1; } for(i=2;i<N;i++){ divide(i); for(j=0;j<tot;j++)f[i][j]+=f[i-1][j]; } for(i=0;i<tot;i++)for(po[i][0]=j=1;j<N;j++)po[i][j]=po[i][j-1]*p[i]; scanf("%d%d",&n,&m); m--; dfs(0,m,0); for(set<ll>::iterator o=T.begin();o!=T.end();o++)printf("%I64u ",*o); }
I. The White Rabbit Pocket Watch
在模$13$意义下高斯消元求出每条边的长度,然后floyd即可。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; typedef pair < int , int > pii ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1005 ; const int mod = 13 ; const int INF = 0x3f3f3f3f ; int pm ( int x , int n ) { int res = 1 ; while ( n ) { if ( n & 1 ) res = res * x % mod ; x = x * x % mod ; n >>= 1 ; } return res ; } int inv[MAXN] ; int val[MAXN] ; vector < int > G[MAXN] ; pii path[MAXN] ; int d[MAXN][MAXN] ; int a[MAXN][MAXN] ; int ans[MAXN] ; int cnt ; int n , s , t , m ; void gauss ( int n , int m ) { int r = 0 , c = 0 ; for ( ; r < n && c < m ; ++ c ) { int tmpr = r ; for ( int i = r ; i < n ; ++ i ) { if ( a[i][c] ) tmpr = i ; } if ( !a[tmpr][c] ) continue ; for ( int i = c ; i <= m ; ++ i ) { swap ( a[r][i] , a[tmpr][i] ) ; } for ( int i = m ; i >= c ; -- i ) { a[r][i] = a[r][i] * inv[a[r][c]] % mod ; } for ( int i = 0 ; i < n ; ++ i ) if ( i != r && a[i][c] ) { for ( int j = m ; j >= c ; -- j ) { a[i][j] = ( a[i][j] - a[r][j] * a[i][c] % mod + mod ) % mod ; } } ++ r ; } } void solve () { cnt = 0 ; clr ( d , -1 ) ; clr ( a , 0 ) ; for ( int i = 0 ; i < MAXN ; ++ i ) { G[i].clear () ; } for ( int i = 0 ; i < m ; ++ i ) { scanf ( "%d" , &val[i] ) ; int x , u , v ; scanf ( "%d" , &x ) ; for ( int j = 0 ; j < x ; ++ j ) { scanf ( "%d" , &v ) ; if ( j ) { if ( d[u][v] == -1 ) { d[u][v] = d[v][u] = cnt ++ ; path[cnt] = pii ( u , v ) ; } G[i].push_back ( d[u][v] ) ; } u = v ; } } for ( int i = 0 ; i < m ; ++ i ) { for ( int j = 0 ; j < G[i].size () ; ++ j ) { a[i][G[i][j]] ++ ; a[i][G[i][j]] %= mod ; } a[i][cnt] = val[i] ; } gauss ( m , cnt ) ; /* for ( int i = 0 ; i < m ; ++ i ) { for ( int j = 0 ; j < cnt ; ++ j ) { printf ( "%d " , a[i][j] ) ; } printf ( "|%d " , a[i][cnt] ) ; } */ clr ( d , INF ) ; for ( int i = 1 ; i <= cnt ; ++ i ) { int u = path[i].first , v = path[i].second , c = a[i - 1][cnt] ; d[u][v] = d[v][u] = c ; } for(int i=1;i<=n;i++)d[i][i]=0; for ( int k = 1 ; k <= n ; ++ k ) { for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 1 ; j <= n ; ++ j ) { d[i][j] = min ( d[i][j] , d[i][k] + d[k][j] ) ; } } } printf ( "%d " , d[s][t] ) ; } int main () { for ( int i = 1 ; i < mod ; ++ i ) { inv[i] = pm ( i , mod - 2 ) ; } int T = 0 ; //scanf ( "%d" , &T ) ; for ( int i = 1 ; i <= T ; ++ i ) { //printf ( "Case #%d: " , i ) ; solve () ; } if ( T ) return 0 ; while ( ~scanf ( "%d%d%d%d" , &n , &s , &t , &m ) ) solve () ; return 0 ; }
J. Risky Lottery
留坑。
K. Balls and Needles
并查集判环。
#include<cstdio> #include<map> #include<algorithm> using namespace std; typedef pair<int,int>P; typedef pair<int,P>PI; const int N=150000; int m,i,e[N][6]; int x,y,f[N],n; map<PI,int>A; map<P,int>B; map<int,int>v[N]; int F(int x){return f[x]==x?x:f[x]=F(f[x]);} inline int getid0(int x,int y,int z){ PI t(x,P(y,z)); if(A[t])return A[t]; return A[t]=++n; } inline int getid1(int x,int y){ P t(x,y); if(B[t])return B[t]; return B[t]=++n; } bool check0(){ n=0; for(i=0;i<N;i++)f[i]=i; for(i=1;i<=m;i++){ x=getid0(e[i][0],e[i][1],e[i][2]); y=getid0(e[i][3],e[i][4],e[i][5]); if(F(x)==F(y))return 1; f[f[x]]=f[y]; } return 0; } bool check1(){ n=0; for(i=0;i<N;i++)f[i]=i; for(i=1;i<=m;i++){ x=getid1(e[i][0],e[i][1]); y=getid1(e[i][3],e[i][4]); //printf("%d %d ",x,y); if(x==y)continue; if(v[x][y])continue; v[x][y]=1; v[y][x]=1; if(F(x)==F(y))return 1; f[f[x]]=f[y]; } return 0; } int main(){ scanf("%d",&m); for(i=1;i<=m;i++){ scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); scanf("%d%d%d",&e[i][3],&e[i][4],&e[i][5]); } if(!check0())puts("No true closed chains");else puts("True closed chains"); if(!check1())puts("No floor closed chains");else puts("Floor closed chains"); }