首页 > 代码库 > XIV Open Cup named after E.V. Pankratiev. GP of SPb
XIV Open Cup named after E.V. Pankratiev. GP of SPb
A. Bracket Expression
直接按题意模拟即可。
时间复杂度$O(n)$。
#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 Maxn=55;char s[Maxn];int ls;LL sta[Maxn];int top=0;int main(){ freopen("bracket-expression.in","r",stdin); freopen("bracket-expression.out","w",stdout); fgets(s,sizeof s,stdin); for(int i=0;(s[i]==‘(‘)||(s[i]==‘)‘);i++){//-1,-2 if(s[i]==‘(‘)sta[top++]=-1; else{ LL cur=1; while(top&&sta[top-1]!=-1){ cur=cur*sta[top-1]; top--; } sta[top-1]=cur+1; } } LL ret=1; while(top)ret=1LL*ret*sta[top-1],top--; printf("%lld\n",ret); return 0;}
B. Checkers
暴力搜索所有对战情况,然后模拟。
时间复杂度$O(2^nk)$。
#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,k;string s[22];int ans=0;int jud(vector<int>&V,string &s){ for(int i=V.size()-1,j=s.size()-1;i>=0&&j>=0;i--,j--){ if(V[i]==(s[j]==‘W‘))continue; if(V[i])return 0; else return 1; } return 1;}void dfs(int cur,int op,int win,vector<int>V){ if(cur>=k){ ans=max(ans,win); return; } for(int i=1;i+cur<=k&&i<=2;i++){ string tmp=s[op]; vector<int>nxt=V; int tmpwin=win; for(int j=0;j<i;j++){ int res=jud(nxt,s[op]); nxt.push_back(res); if(res)tmpwin++; s[op].push_back(res?‘B‘:‘W‘);//res==1:w } dfs(cur+i,(op+1)%n,tmpwin,nxt); s[op]=tmp; }}int main(){ freopen("checkers.in","r",stdin); freopen("checkers.out","w",stdout); scanf("%d%d",&n,&k); for(int i=0;i<n;i++)cin>>s[i]; vector<int>V; dfs(0,0,0,V); printf("%d\n",ans); return 0;}
C. Convex and Compact
枚举起点,设$f[i][j][k]$表示当前凸包转到了$i$点,凸包上和内部有$j$个点,凸包上有$k$个点时凸包的最小周长,然后DP即可。
时间复杂度$O(n^4k)$。
#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 = 65 ;const double INF = 1e60 ;const double eps = 1e-8 ;const double pi = acos ( -1.0 ) ;int dcmp ( double x ) { return ( x > eps ) - ( x < -eps ) ;}struct Point { int x , y ; Point () {} Point ( int x , int y ) : x ( x ) , y ( y ) {} bool operator < ( const Point& a ) const { return x != a.x ? x < a.x : y < a.y ; } Point operator + ( const Point& a ) const { return Point ( x + a.x , y + a.y ) ; } Point operator - ( const Point& a ) const { return Point ( x - a.x , y - a.y ) ; } int operator * ( const Point& a ) const { return x * a.y - y * a.x ; } double angle () { return atan2 ( y , x ) ; } double len () { return sqrt ( 0.0 + x * x + y * y ) ; }} ;struct Node { double r ; int idx ; bool operator < ( const Node& a ) const { return r < a.r ; }} ;struct Pre { int x , y , z ; Pre () {} Pre ( int x , int y , int z ) : x ( x ) , y ( y ) , z ( z ) {}} ;Node a[MAXN] ;Point p[MAXN] ;int n , K ;int in[MAXN][MAXN] ;Pre pre[MAXN][MAXN][17] ;double len2[MAXN][MAXN] ;double dp[MAXN][MAXN][17] ;double ans ;int S[MAXN] , top ;int vis[MAXN] ;int id[MAXN] ;int cmp ( const int&a , const int& b ) { return p[a].x != p[b].x ? p[a].x < p[b].x : p[a].y < p[b].y ;}bool PointInTri ( int i , int j , int k , int l ) { LL a = ( p[i] - p[l] ) * ( p[j] - p[l] ) ; LL b = ( p[j] - p[l] ) * ( p[k] - p[l] ) ; LL c = ( p[k] - p[l] ) * ( p[i] - p[l] ) ; return a * b > 0 && b * c > 0 && c * a > 0 ;}void insert ( int x , int y , int z ) { Pre t = pre[x][y][z] ; if ( t.x ) insert ( t.x , t.y , t.z ) ; S[top ++] = a[x].idx ;}void calc ( int m ) { for ( int i = 0 ; i <= m ; ++ i ) { for ( int j = 0 ; j <= m + 1 ; ++ j ) { for ( int k = 0 ; k <= K ; ++ k ) { dp[i][j][k] = INF ; pre[i][j][k] = Pre ( 0 , 0 , 0 ) ; } } for ( int j = 0 ; j <= m ; ++ j ) { len2[i][j] = ( p[a[i].idx] - p[a[j].idx] ).len () ; } } for ( int i = 1 ; i <= m ; ++ i ) { for ( int j = i + 1 ; j <= m ; ++ j ) { in[i][j] = 3 ; for ( int l = 1 ; l <= m ; ++ l ) if ( l != i && l != j ) { if ( PointInTri ( a[0].idx , a[i].idx , a[j].idx , a[l].idx ) ) { in[i][j] ++ ; } } } } for ( int i = 1 ; i <= m ; ++ i ) { dp[i][2][2] = len2[0][i] * 2 ; pre[i][2][2] = Pre ( 0 , 0 , 0 ) ; for ( int j = 2 ; j <= m ; ++ j ) { for ( int k = 3 ; k <= min ( i + 1 , K ) ; ++ k ) { for ( int l = 1 ; l < i ; ++ l ) if ( dp[l][j][k - 1] < 1e50 ) { int num = j + in[l][i] - 2 ; double tmp = dp[l][j][k - 1] - len2[0][l] + len2[0][i] + len2[i][l] ; if ( dp[i][num][k] > tmp ) { dp[i][num][k] = tmp ; //printf ( "%d %d %d %.5f\n" , i , num , k , dp[i][num][k] ) ; pre[i][num][k] = Pre ( l , j , k - 1 ) ; } } } } } int x = -1 , y , z ; for ( int i = 1 ; i <= m ; ++ i ) { for ( int j = K ; j <= m + 1 ; ++ j ) { for ( int k = 3 ; k <= K ; ++ k ) if ( dp[i][j][k] < 1e50 ) { //printf ( "dp[%d][%d][%d] = %.5f\n" , i , j , k , dp[i][j][k] ) ; if ( dcmp ( dp[i][j][k] - ans ) < 0 ) { ans = dp[i][j][k] ; x = i ; y = j ; z = k ; } } } } if ( ~x ) { top = 0 ; insert ( x , y , z ) ; S[top ++] = a[0].idx ; }}int check ( int x ) { LL f = ( p[x] - p[S[0]] ) * ( p[x] - p[S[1]] ) ; for ( int i = 0 ; i < top ; ++ i ) { LL ff = ( p[x] - p[S[i]] ) * ( p[x] - p[S[( i + 1 ) % top]] ) ; if ( f * ff < 0 ) return 0 ; } return 1 ;}void solve () { ans = INF ; for ( int i = 1 ; i <= n ; ++ i ) { scanf ( "%d%d" , &p[i].x , &p[i].y ) ; } if ( K == 1 ) { printf ( "%d\n" , 0 ) ; printf ( "%d\n" , 1 ) ; return ; } if ( K == 2 ) { int x , y ; for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = i + 1 ; j <= n ; ++ j ) { double tmp = ( p[i] - p[j] ).len () ; if ( tmp < ans ) { ans = tmp ; x = i ; y = j ; } } } printf ( "%.8f\n" , ans ) ; printf ( "%d %d\n" , x , y ) ; return ; } for ( int i = 1 ; i <= n ; ++ i ) { id[i] = i ; } sort ( id + 1 , id + n + 1 , cmp ) ; a[0].r = -INF ; for ( int i = 1 ; i <= n ; ++ i ) { int m = 0 ; for ( int j = i + 1 ; j <= n ; ++ j ) { ++ m ; a[m].idx = id[j] ; a[m].r = ( p[id[j]] - p[id[i]] ).angle () ; //if ( dcmp ( a[j].r ) < 0 ) a[j].r = 2 * pi + a[j].r ; } a[0].idx = id[i] ; sort ( a + 1 , a + m + 1 ) ; if ( m + 1 >= K ) calc ( m ) ; } printf ( "%.8f\n" , ans ) ; int flag = 0 ; clr ( vis , 0 ) ; for ( int i = 0 ; i < top ; ++ i ) { if ( flag ) printf ( " " ) ; flag = 1 ; printf ( "%d" , S[i] ) ; vis[S[i]] = 1 ; } for ( int i = top + 1 ; i <= K ; ++ i ) { for ( int j = 1 ; j <= n ; ++ j ) if ( !vis[j] ) { if ( check ( j ) ) { printf ( " %d" , j ) ; vis[j] = 1 ; break ; } } } puts ( "" ) ;}int main () { freopen ( "convexset.in" , "r" , stdin ) ; freopen ( "convexset.out" , "w" , stdout ) ; while ( ~scanf ( "%d%d" , &n , &K ) ) solve () ; return 0 ;}
D. Forbidden Words
留坑。
E. Four Prime Numbers
设$f[i]$表示用两个质数能拼出$i$的方案数,可以通过暴力枚举两个质数求出,则$ans=\sum f[i]f[n-i]$。
时间复杂度$O(\frac{n^2}{\ln^2n})$。
#include<cstdio>const int N=100010;int n,i,j,tot,v[N],p[N],f[N];long long ans;int main(){ freopen("fourprimes.in","r",stdin); freopen("fourprimes.out","w",stdout); scanf("%d",&n); for(i=2;i<=n;i++){ if(!v[i])p[tot++]=i; for(j=0;j<tot;j++){ if(i*p[j]>n)break; v[i*p[j]]=1; if(i%p[j]==0)break; } } for(i=0;i<tot;i++){ if(p[i]+p[i]<=n)f[p[i]+p[i]]++; for(j=0;j<i;j++){ if(p[i]+p[j]>n)break; f[p[i]+p[j]]+=2; } } for(i=1;i<=n;i++)ans+=1LL*f[i]*f[n-i]; printf("%lld",ans); return 0;}
F. Set Intersection
随机化找出规律:$ans=\lfloor\frac{LM}{N}\rfloor$。
#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 LIM=1000;int a[1000020],b[1000020];int n,l,m;int c[1000020],ans[1000020];int main(){ freopen("intset.in","r",stdin); freopen("intset.out","w",stdout); while(scanf("%d%d%d",&n,&l,&m)!=EOF){ long long now=1LL*m*l/n; printf("%lld",now);/* for(int i=0;i<n;i++)b[i]=i; for(int i=0;i<LIM;i++){ random_shuffle(b,b+n); int cur=0; for(int j=0;j<m;j++){ if(b[j]<l)cur++; } ans[cur]++; } for(int i=n-1;i>=0;i--)ans[i]+=ans[i+1]; int rep=0; for(int i=n;i>=0;i--){ if(ans[i]>=LIM/2){ rep=i; break; } } printf("%d\n",rep);*/ } return 0;}
G. Medals
将第$x$名的费用设置为$1001^{10-x}$,那么答案就是二分图最大权匹配,费用流求解即可,需要用__int128存储。
#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 __int128 LL;typedef pair<int,int>pi;const int Maxn=2020,Maxe=200020;LL Inf=1LL<<60;LL pw[15];int ne;int n,s,t;vector<int>G[Maxn];struct E{ int v,c; LL w; E(){} E(int v,int c,LL w):v(v),c(c),w(w){}}e[Maxe];void add(int u,int v,int c,LL w){ e[ne]=E(v,c,w); G[u].push_back(ne++); e[ne]=E(u,0,-w); G[v].push_back(ne++);}int pre[Maxn],pe[Maxn],inq[Maxn];LL d[Maxn];bool spfa(){ for(int i=0;i<=t;i++)d[i]=Inf,inq[i]=0; d[s]=0; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<G[u].size();i++){ int id=G[u][i]; int v=e[id].v; LL w=e[id].w; int c=e[id].c; if(!c)continue; if(d[v]>d[u]+w){ pre[v]=u; pe[v]=id; d[v]=d[u]+w; if(!inq[v]){q.push(v);inq[v]=1;} } } inq[u]=0; } return d[t]<0;}int rep[100];int cho[Maxn];void costflow(){ LL ans=0; while(spfa()){ ans-=d[t]; for(int i=t;i!=s;i=pre[i]){ e[pe[i]].c--; e[pe[i]^1].c++; } } for(int i=0;i<10;i++)rep[10-i]=ans%1001,ans/=1001; for(int i=1;i<=10;i++)printf("%d%c",rep[i],i==10?‘\n‘:‘ ‘); for(int i=1;i<=n;i++){ cho[i]=0; for(int j=0;j<G[i].size();j++){ int id=G[i][j]; if(e[id].v!=s&&(!e[id].c)){ cho[i]=e[id].v-n; } } } for(int i=1;i<=n;i++)printf("%d%c",cho[i],i==n?‘\n‘:‘ ‘);}int main(){ freopen("medals.in","r",stdin); freopen("medals.out","w",stdout); pw[0]=1; Inf*=Inf; for(int i=1;i<=11;i++)pw[i]=pw[i-1]*1001; scanf("%d",&n); for(int i=1;i<=n;i++){ int k;scanf("%d",&k); for(int j=0;j<k;j++){ int id,rk; scanf("%d%d",&id,&rk); add(i,id+n,1,-pw[10-rk]); } add(s,i,1,0); } s=0;t=n+1000+1; for(int i=n+1;i<t;i++)add(i,t,1,0); costflow(); return 0;}
H. Reachability
对于每个询问,压位记忆化搜索即可。
时间复杂度$O(\frac{qn^3}{64})$。
#include<cstdio>#include<bitset>using namespace std;typedef unsigned int U;const int N=405;typedef bitset<N>DS;int n,m,i,A,B;bool g[N][N],v[N];U pa[N],pb[N];DS f[N];void dfs(int x){ if(v[x])return; v[x]=1; for(int i=1;i<=n;i++)if(g[x][i]){ dfs(i); f[x]|=f[i]; }}inline void vio(){ int i,j; for(i=1;i<=n;i++){ v[i]=0,f[i].reset(); f[i][i]=1; } for(i=1;i<=n;i++)if(!v[i])dfs(i); U ret=0; for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(f[i][j]==1&&i!=j){// printf("%d->%d\n",i,j); ret+=pa[i-1]*pb[j-1]; } printf("%u\n",ret);}int main(){ freopen("reachability.in","r",stdin); freopen("reachability.out","w",stdout); scanf("%d%d%d%d",&n,&m,&A,&B); for(pa[0]=i=1;i<=n;i++)pa[i]=pa[i-1]*A; for(pb[0]=i=1;i<=n;i++)pb[i]=pb[i-1]*B; for(i=1;i<=m;i++){ char op1[5],op2[5]; int x,k,y; scanf("%s%s%d%d",op1,op2,&x,&k); if(op2[0]==‘o‘){ while(k--)scanf("%d",&y),g[x][y]^=1; }else{ while(k--)scanf("%d",&y),g[y][x]^=1; } vio(); } return 0;}
I. Revolving Lasers
留坑。
J. Snakes on the Stone
从蛇头开始走,每次碰到交点就往上走即可,这样一定可以保证不打结。
#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 = 30 ;int a[MAXN][MAXN] , n , m[3] ;int vis[MAXN][MAXN] ;int x[3][MAXN * MAXN] , y[3][MAXN * MAXN] ;void solve () { clr ( a , 0 ) ; clr ( vis , 0 ) ; for ( int i = 0 ; i < n ; ++ i ) { scanf ( "%d" , &m[i] ) ; for ( int j = 1 ; j <= m[i] ; ++ j ) { scanf ( "%d%d" , &x[i][j] , &y[i][j] ) ; vis[x[i][j]][y[i][j]] ++ ; } } for ( int i = 0 ; i < n ; ++ i ) { for ( int j = 1 ; j <= m[i] ; ++ j ) { int r = x[i][j] , c = y[i][j] ; if ( vis[r][c] == 2 ) { if ( !a[r][c] ) { ++ a[r][c] ; putchar ( ‘-‘ ) ; } else { putchar ( ‘+‘ ) ; } } } puts ( "" ) ; }}int main () { freopen ( "snakes2.in" , "r" , stdin ) ; freopen ( "snakes2.out" , "w" , stdout ) ; while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ;}
K. Dependent Subsets
选出的这些向量的秩只能是$1$或$2$,枚举一个基向量,用它去对其它向量进行消元,约分之后排序,首先被消完的向量都可以选入,然后再选若干个约分后完全相等的向量即可。
时间复杂度$O(n^2d)$。
#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 Maxn=1020;int n,d;vector<int> a[Maxn];vector<int> b[Maxn];int id[Maxn];int use[Maxn];int st[Maxn];bool cmp(int t1,int t2){ return b[t1]<b[t2];}int xiao(vector<int>&x){//return first nonzero loc int fst=x.size(); for(int i=0;i<x.size();i++){ if(x[i]!=0){fst=i;break;} } if(fst>=x.size())return fst; int gc=abs(x[fst]); for(int i=fst+1;i<x.size();i++){ if(x[i]!=0){ gc=__gcd(abs(x[i]),gc); } } int tmp=x[fst]<0?(-gc):gc; for(int i=fst;i<x.size();i++){ if(x[i]!=0)x[i]=x[i]/tmp; } return fst;}vector<int> dec(vector<int>&x,vector<int>&y,int st1,int st2){ if(!y[st1])return y; vector<int>ret=x; int lcm=x[st1]*abs(y[st1])/__gcd(x[st1],abs(y[st1])); int be1=lcm/x[st1],be2=lcm/y[st1]; for(int i=0;i<x.size();i++)ret[i]=x[i]*be1-y[i]*be2; return ret;}void pt(vector<int>&x){ for(int i=0;i<x.size();i++)printf("%d ",x[i]);puts("");}bool iszero(vector<int>&x){ for(int i=0;i<x.size();i++)if(x[i])return 0; return 1;}int main(){ freopen("subset.in","r",stdin); freopen("subset.out","w",stdout); scanf("%d%d",&n,&d); for(int i=1;i<=n;i++){ for(int j=0;j<d;j++){ int x;scanf("%d",&x); a[i].push_back(x); } } for(int i=1;i<=n;i++)st[i]=xiao(a[i]); vector<int>rep; for(int i=1;i<=n;i++){ int cnt=0; for(int j=i+1;j<=n;j++){ b[cnt]=dec(a[i],a[j],st[i],st[j]); xiao(b[cnt]); use[cnt]=cnt; id[cnt]=j; cnt++; } sort(use,use+cnt,cmp); int sel=-1,sr; int now=0; vector<int>tmp; tmp.push_back(i); for(;now<cnt&&iszero(b[use[now]]);now++)tmp.push_back(id[use[now]]); int tmpans=0; for(int j=now,k;j<cnt;j=k){ for(k=j+1;k<cnt&&b[use[k]]==b[use[j]];k++); if((k-j)>tmpans){ sel=j; sr=k; tmpans=k-j; } } if(sel>=0){ for(int j=sel;j<sr;j++)tmp.push_back(id[use[j]]); } if(tmp.size()>rep.size())swap(tmp,rep); } printf("%d\n",(int)rep.size()); for(int i=0;i<rep.size();i++)printf("%d%c",rep[i],i==rep.size()-1?‘\n‘:‘ ‘); return 0;}
XIV Open Cup named after E.V. Pankratiev. GP of SPb