A. Nanoassembly
首先用叉积判断是否在指定向量右侧,然后解出法线与给定直线的交点,再关于交点对称即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; typedef pair<int,int>pi; 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);} P operator*(double v){return P(x*v,y*v);} double len(){return hypot(x,y);} double len_sqr(){return x*x+y*y;} P rot90(){return P(-y,x);} }a[111111],A,B; const double eps=1e-8; int sgn(double x){ if(x<-eps)return -1; if(x>eps)return 1; return 0; } double cross(P a,P b){ return a.x*b.y-a.y*b.x; } P line_intersection(P a,P b,P p,P q){ double U=cross(p-a,q-p),D=cross(b-a,q-p); return a+(b-a)*(U/D); } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); int n,m,i; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%lf%lf",&a[i].x,&a[i].y); while(m--){ scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y); P t=B-A; t=t.rot90(); //printf("t=%.4f %.4f ",t.x,t.y); for(i=1;i<=n;i++)if(cross(a[i]-A,B-A)>0){ P o=line_intersection(A,B,a[i],a[i]+t); //printf("->%d %.4f %.4f ",i,(a[i]+t).x,(a[i]+t).y); a[i]=(o*2.0)-a[i]; } //for(i=1;i<=n;i++)printf("%.4f %.4f ",a[i].x,a[i].y); } for(i=1;i<=n;i++)printf("%.8f %.8f ",a[i].x,a[i].y); return 0; }
B. Playoff
建树根据dfs括号序列判断是否成祖孙关系即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; int n; string name[Maxn]; map<string,int>id; int a[Maxn<<2]; char s[Maxn]; bool check(int id1,int id2){ id1+=n;id2+=n; for(int i=id2;i;i>>=1)if(a[i]==id1)return 1; return 0; } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while(scanf("%d",&n)!=EOF){ n=1<<n; id.clear(); for(int i=0;i<n;i++) cin>>name[i],id[name[i]]=i,a[n+i]=n+i; int cur=n>>1,tot=0; scanf("%s",s); //printf("sss=%s ",s); for(;cur;cur>>=1){ for(int i=cur;i<cur<<1;i++){ char c=s[tot++]; if(c=='W')a[i]=a[i<<1]; else a[i]=a[i<<1|1]; } } int q;scanf("%d",&q); //printf("q=%d ",q); while(q--){ string s1,s2; cin>>s1>>s2; int id1=id[s1],id2=id[s2]; if(check(id1,id2)){ puts("Win"); } else if(check(id2,id1)){puts("Lose");} else puts("Unknown"); } } }
C. Inequalities
差分约束系统,下界直接作为初始值,然后判断是否出现正环或者超过上限,需要SLF优化。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1000005 ; const int MAXE = 1000005 ; 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] , vis[MAXN] , cnt[MAXN] , Q[MAXN] , head , tail ; int maxv[MAXN] ; int n , m ; 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 ++ ; } int spfa () { while ( head != tail ) { int u = Q[head ++] ; if ( head == MAXN ) head = 0 ; vis[u] = 0 ; for ( int i = H[u] ; ~i ; i = E[i].n ) { //if ( clock () > 1.99 * CLOCKS_PER_SEC ) return 0 ; int v = E[i].v ; if ( d[v] < d[u] + E[i].c ) { d[v] = d[u] + E[i].c ; if ( d[v] > maxv[v] ) return 0 ; if ( !vis[v] ) { vis[v] = 1 ; cnt[v] ++ ; if ( cnt[v] == n + 1 ) return 0 ; if ( d[Q[head]] < d[v] ) { -- head ; if ( head < 0 ) head = MAXN - 1 ; Q[head] = v ; } else { Q[tail ++] = v ; if ( tail == MAXN ) tail = 0 ; } } } } } return 1 ; } void solve () { init () ; int ok = 1 ; head = tail = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { d[i] = -2e9 ; maxv[i] = 2e9 ; Q[tail ++] = i ; vis[i] = 1 ; cnt[i] = 0 ; } for ( int i = 0 ; i < m ; ++ i ) { int op , x , xv , y , yv ; scanf ( "%d%d%d%d%d" , &op , &x , &xv , &y , &yv ) ; if ( x == 0 ) { if ( y == 0 ) addedge ( xv , yv , op ) ; else maxv[xv] = min ( maxv[xv] , yv - op ) ; } else { if ( y == 0 ) d[yv] = max ( d[yv] , xv + op ) ; else if ( xv + op > yv ) ok = 0 ; } } if ( !ok || !spfa () ) { puts ( "NO" ) ; return ; } puts ( "YES" ) ; for ( int i = 1 ; i <= n ; ++ i ) { printf ( "%d " , d[i] ) ; } } int main () { freopen ( "input.txt" , "r" , stdin ) ; freopen ( "output.txt" , "w" , stdout ) ; while ( ~scanf ( "%d%d" , &m , &n ) ) solve () ; return 0 ; }
D. How to measure the Ocean?
按$s imes p$从小到大排序,然后二分答案,尽量延伸每条线段的长度,看看是否达到$d$即可。
#include <bits/stdc++.h> using namespace std ; const int MAXN = 100005 ; struct Node { int p , a ; bool operator < ( const Node& t ) const { return p < t.p ; //return min ( a - p , t.a - p - t.p ) > min ( a - p - t.p , t.a - t.p ) ; } } ; Node a[MAXN] ; int d , n ; void solve () { int S , P , A ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d%d%d" , &S , &P , &A ) ; a[i].p = S * P ; a[i].a = S * A ; } sort ( a + 1 , a + n + 1 ) ; double l = 0 , r = 1e6 ; for ( int o = 0 ; o <= 100 ; ++ o ) { double x = ( l + r ) / 2 , mid = x ; double D = 0 ; int ok = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { double l = max ( 0.0 , 1.0 * ( a[i].a - x ) / a[i].p ) ; D += l ; x += l * a[i].p ; if ( D >= d ) { ok = 1 ; break ; } } if ( ok ) l = mid ; else r = mid ; } printf ( "%.10f " , l ) ; } int main () { freopen ( "input.txt" , "r" , stdin ) ; freopen ( "output.txt" , "w" , stdout ) ; while ( ~scanf ( "%d%d" , &d , &n ) ) solve () ; return 0 ; }
E. Navigation
建图跑最短路即可。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1605 ; const double INF = 1e50 ; int n , m , k , vr , vf ; double d[MAXN] , G[MAXN][MAXN] ; int vis[MAXN] , p[MAXN] ; int x[MAXN] , y[MAXN] ; vector < int > S ; double get_dis ( int x , int y ) { return sqrt ( 1.0 * x * x + 1.0 * y * y ) ; } void dij ( int s ) { for ( int i = 1 ; i <= n ; ++ i ) { d[i] = INF ; vis[i] = 0 ; p[i] = 0 ; } d[s] = 0 ; for ( int i = 1 ; i < n ; ++ i ) { double minv = INF ; int u = s ; for ( int j = 1 ; j <= n ; ++ j ) { if ( !vis[j] && d[j] < minv ) { minv = d[j] ; u = j ; } } vis[u] = 1 ; for ( int j = 1 ; j <= n ; ++ j ) { if ( !vis[j] && d[u] + G[u][j] < d[j] ) { d[j] = d[u] + G[u][j] ; p[j] = u ; } } } } void insert ( int o ) { if ( p[o] ) { insert ( p[o] ) ; S.push_back ( p[o] ) ; } } void solve () { S.clear () ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d%d" , &x[i] , &y[i] ) ; for ( int j = 1 ; j <= i ; ++ j ) { G[i][j] = G[j][i] = get_dis ( x[i] - x[j] , y[i] - y[j] ) / vf ; } } for ( int i = 0 ; i < m ; ++ i ) { int u , v ; scanf ( "%d%d" , &u , &v ) ; G[u][v] = G[v][u] = G[u][v] * vf / vr ; } int pre = 1 , now ; double ans = 0 ; for ( int i = 1 ; i <= k ; ++ i ) { scanf ( "%d" , &now ) ; dij ( pre ) ; insert ( now ) ; ans += d[now] ; pre = now ; } dij ( now ) ; insert ( n ) ; ans += d[n] ; S.push_back ( n ) ; printf ( "%.10f " , ans ) ; for ( int i = 0 ; i < S.size () ; ++ i ) { i && putchar ( ' ' ) ; printf ( "%d" , S[i] ) ; } puts ( "" ) ; } int main () { freopen ( "input.txt" , "r" , stdin ) ; freopen ( "output.txt" , "w" , stdout ) ; while ( ~scanf ( "%d%d%d%d%d" , &n , &m , &k , &vr , &vf ) ) solve () ; return 0 ; }
F. Bets
根据题意模拟即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; typedef pair<int,int>pi; void scan(LL &x){ char s[10];scanf("%s",s); int ned=5; int has=0; x=0; for(int i=0;s[i];i++){ if(s[i]=='.'){ has=1; continue; } x=x*10+s[i]-'0'; if(has)ned--; } for(int i=0;i<ned;i++)x=x*10; } int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); int _;scanf("%d",&_); while(_--){ LL a,b,c; scan(a); scan(b); scan(c); LL tot=a*b*c; LL res=tot/a+tot/b+tot/c; //printf("a=%lld b=%lld c=%lld ",a,b,c); //printf("res=%lld tot=%lld ",res,tot); if(res*100000<tot)puts("YES"); else puts("NO"); } }
G. Ant on the road
留坑。
H. Bouquet
将花按照颜色排序,设$f[i][j][k]$表示考虑了前$i$朵花,总价值为$j$,第$i$种花所在的颜色是否需要计入答案为$k$时颜色数的最大值,然后DP即可。
时间复杂度$O(nS)$。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; typedef pair<int,int>pi; int n,S; pi a[Maxn]; int dp[2][50020][2]; void up(int &x,int y){x=max(x,y);} int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while(scanf("%d%d",&n,&S)!=EOF){ for(int i=0;i<n;i++){ scanf("%d%d",&a[i].first,&a[i].second); } sort(a,a+n); memset(dp,-1,sizeof dp); dp[0][0][0]=0; int cs=0; for(int i=0;i<n;i++){ int islast=(i==n-1)||(a[i+1].first!=a[i].first); memset(dp[cs^1],-1,sizeof dp[cs^1]); int w=a[i].second; for(int j=0;j<=S;j++){ int nw=w+j; //if(nw>S)continue; for(int k=0;k<2;k++){ int val=dp[cs][j][k]; if(val<0)continue; up(dp[cs^1][j][islast?0:k],val); if(nw>S)continue; up(dp[cs^1][nw][islast?0:1],val+(k!=1)); } } cs^=1; } int ans=max(dp[cs][S][0],dp[cs][S][1]); if(ans<0)puts("Impossible"); else printf("%d ",ans); } }
I. Hash function
倒着解出初始值即可。
#include<cstdio> typedef unsigned int UI ; UI Hash ( UI v ) { v = v + ( v << 10 ) ; v = v ^ ( v >> 6 ) ; v = v + ( v << 3 ) ; v = v ^ ( v >> 11 ) ; v = v + ( v << 16 ) ; return v; } typedef long long ll; ll exgcd(ll a,ll b,ll&x,ll&y){ if(!b)return x=1,y=0,a; ll d=exgcd(b,a%b,x,y),t=x; return x=y,y=t-a/b*y,d; } ll cal(ll a,ll b,ll n){ ll x,y,d=exgcd(a,n,x,y); x=(x%n+n)%n; return x*(b/d)%(n/d); } UI F(UI v,int B){ ll a=(1U<<B)+1; ll b=v; ll n=1LL<<32; return cal(a,b,n); } UI G11(UI v){ UI G=v>>21,H=(v>>10)&((1U<<11)-1),I=v&((1U<<10)-1); UI A=G; UI B=H^A; UI C=I^(B>>1); return (A<<21)|(B<<10)|(C); } UI G6(UI v){ UI a=v>>26,b=(v>>20)&((1U<<6)-1),c=(v>>14)&((1U<<6)-1), d=(v>>8)&((1U<<6)-1),e=(v>>2)&((1U<<6)-1),f=v&((1U<<2)-1); UI A=a; UI B=A^b; UI C=B^c; UI D=C^d; UI E=D^e; UI F=(E>>4)^f; return (A<<26)|(B<<20)|(C<<14)|(D<<8)|(E<<2)|F; } UI Hash2 ( UI v ) { v = F(v,16); v = G11(v); v = F(v,3); v = G6(v); v = F(v,10); return v; } int cal(UI v){ UI t=v; for(int i=1;;i++){ t=Hash(t); if(t==v)return i; } } UI n ; int main () { freopen ( "input.txt" , "r" , stdin ) ; freopen ( "output.txt" , "w" , stdout ) ; int T ; scanf ( "%d" , &T ) ; while ( T -- ) { scanf ( "%u" , &n ) ; printf ( "%u " , Hash2 ( n ) ) ; } return 0 ; }
J. Civilization
留坑。
K. Master Gambs chairs
每个集合取最小的即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; int n,S; vector<int>V[Maxn]; int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while(scanf("%d%d",&n,&S)!=EOF){ vector<int>tmp; for(int i=1;i<=n;i++)V[i].clear(); for(int i=1;i<=n;i++){ int x,y;scanf("%d%d",&x,&y); V[x].push_back(y); } for(int i=1;i<=n;i++){ if(!V[i].size())continue; sort(V[i].begin(),V[i].end()); tmp.push_back(V[i][0]); } sort(tmp.begin(),tmp.end()); LL cur=0; int ans=0; for(int i=0;i<tmp.size();i++){ if(cur+tmp[i]<=S){ cur+=tmp[i]; ans++; } else break; } printf("%d ",ans); } }
L. Scrabble
根据题意模拟即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; typedef pair<int,int>pi; int n,m; int di[2][2]={{1,0},{0,1}}; int Mp[22][22]; int col[22][22]; int ltc[]={1,1,2,3,1,1}; int wc[]={1,1,1,1,2,3}; int ans[11]; int base[]={0,1,3,2,3,2,1,5,5,1,2,2,2,2,1,1,2,2,2,2,3,10,5,10,5,10,10,10 ,5,5,10,10,3}; int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); col[1][1]=5; for(int i=2;i<=5;i++){ col[i][i]=4; } col[6][2]=col[2][6]=3; col[4][1]=col[1][4]=col[3][7]=col[7][3]=col[7][7]=2; for(int i=1;i<=7;i++){ for(int j=1;j<=7;j++){ col[16-i][j]=col[i][16-j]=col[i][j]; } } col[8][1]=col[1][8]=col[8][15]=col[15][8]=5; col[8][4]=col[4][8]=col[8][12]=col[12][8]=2; col[8][8]=1; for(int i=1;i<=7;i++){ for(int j=9;j<=15;j++){ col[16-i][j]=col[i][j]; } } scanf("%d%d",&n,&m); //puts("ok"); for(int i=1,turn=0;i<=m;i++,(turn=(turn+1)%n)){ int k;scanf("%d",&k); //printf("kk=%d ",k); int cnt=0; for(int it=0;it<k;it++){ char d; int curx,cury; int num;scanf("%d %c%d%d",&num,&d,&curx,&cury); int ty=d=='h'?0:1; int tmp=0,mul=1; for(int it2=0;it2<num;it2++){ int x;scanf("%d",&x); if(!Mp[curx][cury])cnt++; Mp[curx][cury]=x; tmp+=base[x]*ltc[col[curx][cury]]; mul*=wc[col[curx][cury]]; curx+=di[ty][0]; cury+=di[ty][1]; } ans[turn]+=tmp*mul; } if(cnt>=7)ans[turn]+=15; } for(int i=0;i<n;i++)printf("%d ",ans[i]); }
总结:
- D题想复杂了,在错误的道路上越走越远,碰到这种情况应该换人想。
- 读题速度需要提高,没有来得及阅读的J题其实也可做。