首页 > 代码库 > XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus
XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus
A. RPG
首先计算出每个技能对于每个属性值的可行区间,若区间为空则不合法。
枚举两个技能,以及每个属性值,根据区间的关系可以得到哪个必须要在另一个之前学,连边看看是否有环即可。
时间复杂度$O(n^2m)$。
#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=1e9;int l[555][555],r[555][555];vector<int>G[555];int cnt[555];int n,m;bool topo(){ queue<int>q; int tot=0; for(int i=1;i<=n;i++){ if(!cnt[i])q.push(i); } while(!q.empty()){ int u=q.front();q.pop();tot++; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; cnt[v]--; if(!cnt[v])q.push(v); } } if(tot<n)return 0; return 1;}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)l[i][j]=0,r[i][j]=Inf; for(int i=1;i<=n;i++){ int k;scanf("%d",&k); for(int j=0;j<k;j++){ char s[4]; int id,val,ty=0; scanf("%d%s%d",&id,s,&val); if(s[0]==‘>‘)l[i][id]=max(l[i][id],val); else r[i][id]=min(r[i][id],val); } } bool flag=1; for(int i=1;i<=n&&flag;i++){ for(int j=1;j<=n&&flag;j++){ bool ned=0;; for(int k=1;k<=m;k++){ if(l[i][k]>r[i][k]){flag=0;break;} if(r[i][k]<l[j][k]){ned=1;break;} } if(i==j)continue; if(ned){ //printf("i=%d j=%d\n",i,j); G[i].push_back(j),cnt[j]++; } } } if(flag&&!topo())flag=0; puts(flag?"Yes":"No"); return 0;}
B. Integer in integer
按KMP的next数组进行数位DP即可,时间复杂度$O(|B||C|)$。
#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 mod=1e9+7;char A[10020],B[10020],C[10020];int num[10020];int dp2[10020][2][2][502];int dp1[10020][2];int lsc;int to[10020][10];int f[555];inline void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}int dfs1(int cur,int can){ if(cur<0)return 1; int &t=dp1[cur][can]; if(t>=0)return t; t=0; for(int i=0;i<10;i++){ if(!can&&i>num[cur])break; int ncan=can||(i<num[cur]); up(t,dfs1(cur-1,ncan)); } return t;}int dfs2(int cur,int qd,int can,int pp){ if(cur<0)return 0; int &t=dp2[cur][qd][can][pp]; if(t>=0)return t; t=0; for(int i=0;i<10;i++){ if(!can&&i>num[cur])break; int ncan=can||(i<num[cur]); int nqd=qd||(i); int npp=to[pp][i]; if(!nqd)npp=0; if(npp>=lsc){ //printf("cur=%d pp=%d can=%d t0=%d\n",cur,can,pp,t); up(t,dfs1(cur-1,ncan)); //printf("cur=%d pp=%d can=%d t0=%d\n",cur,can,pp,t); up(t,dfs2(cur-1,nqd,ncan,f[lsc])); } else{ up(t,dfs2(cur-1,nqd,ncan,npp)); } } //if(t&&cur<=2)printf("%d %d %d t=%d\n",cur,can,pp,t); return t;}int solve(char *A){ int ls=strlen(A); reverse(A,A+ls); memset(num,0,sizeof num); for(int i=0;i<ls;i++)num[i]=A[i]-‘0‘; memset(dp1,-1,sizeof dp1); memset(dp2,-1,sizeof dp2); //printf("",dfs1(0,)); int ret=dfs2(10000,0,0,0); //printf("ret=%d\n",ret); return ret;}void getf(){ f[0]=f[1]=0; for(int i=1;i<lsc;i++){ int j=f[i]; while(j&&(C[i]!=C[j]))j=f[j]; if(C[i]==C[j])f[i+1]=j+1; else f[i+1]=0; } for(int i=0;i<lsc;i++){ for(int j=0;j<10;j++){ int t=i; while(t&&((j+‘0‘)!=C[t]))t=f[t]; if(C[t]==(j+‘0‘))to[i][j]=t+1; else to[i][j]=0; } }}int main(){ scanf("%s%s%s",A,B,C); lsc=strlen(C); getf(); int ans=0; for(int i=0,j=0;A[i];i++){ while(j&&A[i]!=C[j])j=f[j]; if(A[i]==C[j])j++; else j=0; if(j==lsc){j=f[lsc];ans++;} } //solve(A); int ans1=solve(A); int ans2=solve(B); //printf("ans1=%d ans2=%d\n",ans1,ans2); ans=((ans2-ans1+mod)%mod+ans)%mod; printf("%d\n",ans); return 0;}
C. Card Game
留坑。
D. Epidemy
DLX重复覆盖,加上卡时即可通过。
#include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define rec( i , A , o ) for ( int i = A[o] ; i != o ; i = A[i] )#define clr( a , x ) memset ( a , x , sizeof a )const int MAXN = 3005 ;const int MAXE = 30005 ;const int MAXNODE = 100005 ;const int INF = 0x3f3f3f3f ;struct DLX { int L[MAXNODE] ; int R[MAXNODE] ; int D[MAXNODE] ; int U[MAXNODE] ; int row[MAXNODE] ; int col[MAXNODE] ; int H[MAXE] ; int S[MAXE] ; int n , k ; int size ; int vis[MAXE] , Time ; int ans ; void init ( int _n , int _k ) { n = _n ; k = _k ; Time = 0 ; clr ( H , -1 ) ; clr ( vis , 0 ) ; For ( i , 0 , n ) { S[i] = 0 ; U[i] = D[i] = i ; L[i] = i - 1 ; R[i] = i + 1 ; } L[0] = n ; R[n] = 0 ; size = n ; ans = INF ; } void link ( int r , int c ) { ++ S[c] ; ++ size ; row[size] = r ; col[size] = c ; D[size] = c ; U[size] = U[c] ; D[U[c]] = size ; U[c] = size ; if ( ~H[r] ) { L[size] = L[H[r]] ; R[size] = H[r] ; R[L[size]] = size ; L[R[size]] = size ; } else L[size] = R[size] = H[r] = size ; } void remove ( int c ) { rec ( i , D , c ) { R[L[i]] = R[i] ; L[R[i]] = L[i] ; } } void resume ( int c ) { rec ( i , U , c ) R[L[i]] = L[R[i]] = i ; } int h () { ++ Time ; int cnt = 0 ; rec ( i , R , 0 ) if ( vis[i] != Time ) { vis[i] = Time ; ++ cnt ; rec ( j , D , i ) rec ( k , R , j ) vis[col[k]] = Time ; } return cnt ; } void dance ( int d ) { if ( clock () >= 2.5 * CLOCKS_PER_SEC ) return ; if ( d + h () >= min ( ans , k + 1 ) ) return ; //printf ( "dep = %d %d %d\n" , d , R[0] , ans ) ; if ( !R[0] ) { ans = min ( d , ans ) ; return ; } int c = R[0] ; rec ( i , R , 0 ) if ( S[i] < S[c] ) c = i ; rec ( i , D , c ) { remove ( i ) ; rec ( j , R , i ) remove ( j ) ; dance ( d + 1 ) ; rec ( j , L , i ) resume ( j ) ; resume ( i ) ; } }} ;DLX dlx ;vector < int > G[MAXN] ;int vis[MAXE] ;int deg[MAXN] ;int n , m , k ;void solve () { dlx.init ( m , k ) ; for ( int i = 1 ; i <= n ; ++ i ) { G[i].clear () ; deg[i] = 0 ; } for ( int i = 1 ; i <= m ; ++ i ) { int u , v ; scanf ( "%d%d" , &u , &v ) ; G[u].push_back ( i ) ; G[v].push_back ( i ) ; ++ deg[u] ; ++ deg[v] ; vis[i] = 0 ; } int ans = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { if ( deg[i] > k ) { ans ++ ; for ( int j = 0 ; j < G[i].size () ; ++ j ) { vis[G[i][j]] = 1 ; } } } //printf ( "ans = %d\n" , ans ) ; if ( ans > k ) { printf ( "Impossible\n" ) ; return ; } for ( int i = 1 ; i <= n ; ++ i ) { if ( deg[i] <= k ) { for ( int j = 0 ; j < G[i].size () ; ++ j ) { if ( !vis[G[i][j]] ) { //printf ( "link %d %d\n" , i , G[i][j] ) ; dlx.link ( i , G[i][j] ) ; } } } } for ( int i = 1 ; i <= m ; ++ i ) if ( vis[i] ) { dlx.R[dlx.L[i]] = dlx.R[i] ; dlx.L[dlx.R[i]] = dlx.L[i] ; } dlx.dance ( ans ) ; if ( dlx.ans <= k ) printf ( "%d\n" , dlx.ans ) ; else printf ( "Impossible\n" ) ;}int main () { while ( ~scanf ( "%d%d%d" , &n , &m , &k ) ) solve () ; return 0 ;}
E. MST
首先求出最小生成树,如果删掉的不是树边,那么答案不变,否则要找到一条经过它的权值最小的非树边来进行替换。
按边权从小到大依次考虑每条非树边,那么就是一个树上染色问题,并查集维护即可。
时间复杂度$O(m\log m)$。
#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 )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 200005 ;const int MAXE = 400005 ;struct Edge { int v , c , n ; Edge () {} Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}} ;struct Node { int u , v , c , id ; bool operator < ( const Node& a ) const { return c < a.c ; }} ;Edge E[MAXE] ;Node a[MAXE] ;int H[MAXN] , cntE ;int pre[MAXN] ;int dep[MAXN] ;int val[MAXN] ;int in[MAXE] ;int be[MAXN] ;LL res[MAXN] ;int p[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 ++ ;}void dfs ( int u , int f ) { for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( v == f ) continue ; pre[v] = u ; dep[v] = dep[u] + 1 ; be[v] = E[i].c ; dfs ( v , u ) ; }}int F ( int x ) { return p[x] == x ? x : ( p[x] = F ( p[x] ) ) ;}void solve () { init () ; for ( int i = 1 ; i <= n ; ++ i ) { p[i] = i ; } for ( int i = 0 ; i < m ; ++ i ) { scanf ( "%d%d%d" , &a[i].u , &a[i].v , &a[i].c ) ; a[i].id = i ; val[i] = -1 ; in[i] = 0 ; } sort ( a , a + m ) ; LL sum = 0 ; int tot = n - 1 ; for ( int i = 0 ; i < m ; ++ i ) { int x = F ( a[i].u ) ; int y = F ( a[i].v ) ; if ( x != y ) { -- tot ; p[x] = y ; in[i] = 1 ; sum += a[i].c ; addedge ( a[i].u , a[i].v , i ) ; addedge ( a[i].v , a[i].u , i ) ; } } if ( tot ) { for ( int i = 0 ; i < m ; ++ i ) { printf ( "-1\n" ) ; } return ; } for ( int i = 1 ; i <= n ; ++ i ) { p[i] = i ; } dfs ( 1 , 1 ) ; for ( int i = 0 ; i < m ; ++ i ) { int u = a[i].u ; int v = a[i].v ; if ( !in[i] ) { while ( 1 ) { int x = F ( a[i].u ) ; int y = F ( a[i].v ) ; if ( x != y ) { if ( dep[x] > dep[y] ) { val[be[x]] = a[i].c ; p[x] = F ( pre[x] ) ; x = F ( pre[x] ) ; } else { val[be[y]] = a[i].c ; p[y] = F ( pre[y] ) ; y = F ( pre[y] ) ; } } else break ; } } } for ( int i = 0 ; i < m ; ++ i ) { if ( !in[i] ) { res[a[i].id] = sum ; } else { if ( ~val[i] ) res[a[i].id] = sum - a[i].c + val[i] ; else res[a[i].id] = -1 ; } } for ( int i = 0 ; i < m ; ++ i ) { printf ( "%lld\n" , res[i] ) ; }}int main () { while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ; return 0 ;}
F. Molecules
将每行倍长,然后依次拼接起来,得到一个序列,构造多项式FFT即可。
时间复杂度$O(n^2\log n)$。
#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>using namespace std ;typedef long long LL ;#define clr( a , x ) memset ( a , x , sizeof a )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 1030 ;const int MAXM = 1030 * 1030 * 4 ;const double pi = acos ( -1.0 ) ;struct Complex { double r , i ; Complex () {} Complex ( double r , double i ) : r ( r ) , i ( i ) {} Complex operator + ( const Complex& t ) const { return Complex ( r + t.r , i + t.i ) ; } Complex operator - ( const Complex& t ) const { return Complex ( r - t.r , i - t.i ) ; } Complex operator * ( const Complex& t ) const { return Complex ( r * t.r - i * t.i , r * t.i + i * t.r ) ; }} ;int n , m ;Complex x1[MAXM] , x2[MAXM] ;LL num[MAXM] ;LL ans[MAXM] ;void FFT ( Complex y[] , int n , int rev ) { for ( int i = 1 , j , k , t ; i < n ; ++ i ) { for ( j = 0 , k = n >> 1 , t = i ; k ; k >>= 1 , t >>= 1 ) { j = j << 1 | t & 1 ; } if ( i < j ) swap ( y[i] , y[j] ) ; } for ( int s = 2 , ds = 1 ; s <= n ; ds = s , s <<= 1 ) { Complex wn ( cos ( rev * 2 * pi / s ) , sin ( rev * 2 * pi / s ) ) ; for ( int k = 0 ; k < n ; k += s ) { Complex w ( 1 , 0 ) , t ; for ( int i = k ; i < k + ds ; ++ i , w = w * wn ) { y[i + ds] = y[i] - ( t = w * y[i + ds] ) ; y[i] = y[i] + t ; } } } if ( rev < 0 ) { for ( int i = 0 ; i < n ; ++ i ) { y[i].r /= n ; } }}int dist ( int x , int y ) { return x * x + y * y ;}void solve () { LL tot = 0 ; double ave = 0 ; int x , n1 = 1 ; clr ( num , 0 ) ; clr ( ans , 0 ) ; m = 2 * n * n ; while ( n1 < 2 * m ) n1 <<= 1 ; for ( int i = 0 ; i < n ; ++ i ) { for ( int j = 0 ; j < n ; ++ j ) { scanf ( "%d" , &x ) ; num[i * 2 * n + j] = x ; tot += x ; ans[0] += x * ( x - 1 ) / 2 ; } } /*for ( int i = 0 ; i < m ; ++ i ) { printf ( "%d " , num[i] ) ; } printf ( "\n" ) ;*/ for ( int i = 0 ; i < m ; ++ i ) { x1[i] = Complex ( num[i] , 0 ) ; x2[i] = Complex ( num[m - i - 1] , 0 ) ; } for ( int i = m ; i < n1 ; ++ i ) { x1[i] = x2[i] = Complex ( 0 , 0 ) ; } FFT ( x1 , n1 , 1 ) ; FFT ( x2 , n1 , 1 ) ; for ( int i = 0 ; i < n1 ; ++ i ) { x1[i] = x1[i] * x2[i] ; } FFT ( x1 , n1 , -1 ) ; /*for ( int i = 0 ; i < n1 ; ++ i ) { printf ( "%d " , ( int ) ( x1[i].r + 0.5 ) ) ; } printf ( "\n" ) ;*/ for ( int i = m ; i < n1 ; ++ i ) { num[i] = ( int ) ( x1[i].r + 0.5 ) ; int x1 = 0 , y1 = 0 ; int x2 = ( i - m + 1 ) / ( 2 * n ) ; int y2 = ( i - m + 1 ) % ( 2 * n ) ; if ( y2 >= n ) { int tmp = n * 2 - y2 ; y1 += tmp ; x2 ++ ; y2 = 0 ; } int dis = dist ( x1 - x2 , y1 - y2 ) ; ans[dis] += num[i] ; ave += sqrt ( 1.0 * dis ) * num[i] ; } tot = tot * ( tot - 1 ) / 2 ; printf ( "%.10f\n" , ave / tot ) ; int cnt = 0 ; for ( int i = 0 ; i < MAXM ; ++ i ) if ( ans[i] ) { printf ( "%d %lld\n" , i , ans[i] ) ; ++ cnt ; if ( cnt >= 10000 ) break ; }}int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ;}
G. Carrier Pigeon
http://blog.csdn.net/huyuncong/article/details/16861281
#include<cstdio>const int N=100,inf=200000000;int n,m,S,T,F,o,i,j,k,t,x,e[1000][5],f[205][N][N],ans;inline void up(int&a,int b){if(a>b)a=b;}int main(){ scanf("%d%d%d%d%d",&n,&m,&S,&T,&F); for(i=0;i<m;i++)for(j=0;j<5;j++)scanf("%d",&e[i][j]); for(o=1;o<=F;o++){ for(i=0;i<n;i++)for(j=0;j<n;j++)if(i!=j)f[o][i][j]=inf; for(i=0;i<m;i++)if(e[i][2]>e[i][3]){ if(o<=e[i][4])t=e[i][2]*o;else t=e[i][2]*e[i][4]+(o-e[i][4])*e[i][3]; up(f[o][e[i][0]][e[i][1]],t); } for(k=0;k<n;k++)for(i=0;i<n;i++)for(j=0;j<n;j++)up(f[o][i][j],f[o][i][k]+f[o][k][j]); } ans=f[F][S][T]; for(x=0;x<m;x++)if(e[x][2]<e[x][3])for(o=1;o<=F;o++){ if(o<=e[x][4])t=e[x][2]*o;else t=e[x][2]*e[x][4]+(o-e[x][4])*e[x][3]; for(i=0;i<n;i++)for(j=0;j<n;j++)up(ans,f[F][S][i]+f[o][i][e[x][0]]+t+f[o][e[x][1]][j]+f[F-o][i][j]+f[F][j][T]); } if(ans<inf)printf("%d",ans);else puts("Impossible"); return 0;}
H. Circles
将第一个圆$10^6$等分,对于那些与第二个圆所在平面距离不超过$eps$的等分点,我们可以近似认为这些点就是第一个圆与第二个圆所在平面的交点,然后判断一下是否同时出现在第二个圆内和圆外的交点即可。
#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;const double pi=acos(-1.0);const double EPS = 1e-4;const double eps=1e-4;struct Point3{ double x,y,z; Point3() {} Point3(double x,double y,double z):x(x),y(y),z(z) {} void in(){ scanf("%lf%lf%lf",&x,&y,&z); } void pt(){ printf("x=%.3f y=%.3f z=%.3f\n",x,y,z); }};typedef Point3 Vec3;Vec3 operator + (Vec3 A,Vec3 B){ return Vec3(A.x + B.x,A.y + B.y,A.z + B.z);}Vec3 operator - (Point3 A,Point3 B){ return Vec3(A.x-B.x,A.y-B.y,A.z-B.z);}Vec3 operator * (Vec3 A,double p){ return Vec3(A.x * p,A.y * p,A.z * p);}Vec3 operator / (Vec3 A,double p){ return Vec3(A.x / p,A.y / p,A.z / p);}int dcmp(double x){ return fabs(x) < EPS ? 0 : (x <0 ? -1:1);}double Dot3(Vec3 A, Vec3 B){ return A.x * B.x + A.y * B.y + A.z * B.z;}double Length3(Vec3 A){ return sqrt(Dot3(A,A));}double Angle(Vec3 A,Vec3 B){ return acos(Dot3(A,B) / Length3(A) / Length3(B));}Vec3 Cross3(Vec3 A,Vec3 B){ return Vec3(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);}double ssin,scos;Point3 rotate(Point3 a,Point3 b){//a Point3 e1,e2,e3; e3=b;double lens=Dot3(a,e3); e1=a-e3*lens; if(Length3(e1)>(1e-6)){e1=e1/Length3(e1);}else return a; e2=Cross3(e1,e3); double xx1=Dot3(a,e2),yy1=Dot3(a,e1),x=xx1*scos-yy1*ssin; double y=xx1*ssin+yy1*scos; return e3*lens+e1*y+e2*x;}struct Plane//平面:单位法向量+点{ Vec3 n; Point3 p0; Plane() {} Plane(Vec3 nn,Point3 pp0) { n = nn/Length3(nn); p0 = pp0; } Plane(Point3 a,Point3 b,Point3 c) { Point3 nn = Cross3(b-a,c-a); n = nn/Length3(nn); p0 = a; }}yuan1,yuan2;Plane jpfPlane(Point3 a1,Point3 a2,Point3 b,Point3 c)//角平分面{ Plane p1 = Plane(a1, b, c),p2 = Plane(a2,c,b); Vec3 temp = p1.n + p2.n; return Plane(Cross3(temp, c-b),b);}Point3 LinePlaneIntersection(Point3 p1,Point3 p2,Plane a)//线面交{ Point3 p0 = a.p0; Vec3 n = a.n,v = p2-p1; double t = (Dot3(n,p0-p1) / Dot3(n,p2-p1)); return p1 + v * t;}Point3 PlaneInsertion(Plane a,Plane b,Plane c)//三面交点{ Vec3 nn = Cross3(a.n,b.n),use = Cross3(nn,a.n); Point3 st = LinePlaneIntersection(a.p0, a.p0+use,b); return LinePlaneIntersection(st, st+nn, c);}double DistanceToPlane(Point3 p,Plane a)//点到面的距离{ Point3 p0 = a.p0; Vec3 n = a.n; return fabs(Dot3(p-p0,n)) / Length3(n);}bool isOnPlane(Point3 a,Point3 b,Point3 c,Point3 d)//判断是否四点共面{ double t = Dot3(d-a,Cross3(b-a, c-a)); return dcmp(t)==0;}bool check(Point3 pp,Plane pl){ //printf("dis=%.12f\n",DistanceToPlane(pp,pl)); return fabs(DistanceToPlane(pp,pl))<eps;}bool solve(Point3 pp){ int LIM=1000000; Point3 npp= yuan2.p0+pp; int ret=0; /*puts("faxiangliang"); yuan2.n.pt(); npp.pt(); */ for(int i=0;i<LIM;i++){ //npp.pt(); //if(!check(npp,yuan2)){printf("i=%d\n",i);puts("wa");} if(check(npp,yuan1)){ // npp.pt(); if(Length3(npp-yuan1.p0)<1-eps)ret|=1; else ret|=2; } double angle=(i+0.0)/LIM*2*pi; scos=cos(angle),ssin=sin(angle); npp=rotate(pp,yuan2.n)+yuan2.p0; } return ret>=3;}int main(){ Point3 o; Vec3 t1,t2; o.in(); t1.in();t2.in(); yuan1=Plane(o,o+t1,o+t2); o.in(); t1.in();t2.in(); yuan2=Plane(o,o+t1,o+t2); if(solve(t1))puts("YES");else puts("NO"); return 0;}
I. Queries
整体二分,用扫描线求出某个区间内的点数即可。
对于排序可以预先在一开始排好序,然后每次递归分治的时候保证不破坏顺序即可。
时间复杂度$O((m+q)\log m)$。
#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;const int N=100010,M=N<<1;int n,m,i,x,y,a[N],e[N][3],cb,cc,qb[M],qc[M],ql[M],qr[M],ans[N];ll f[N],g[N];struct E{int x,y,t;E(){}E(int _x,int _y,int _t){x=_x,y=_y,t=_t;}}b[M],c[M];inline bool cmp(const E&a,const E&b){return a.x<b.x;}inline int lower(int x){ int l=1,r=n,mid,t; while(l<=r)if(a[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1; return t;}void solve(int l,int r,int bl,int br,int cl,int cr){ if(bl>br||cl>cr)return; if(l==r){ for(int i=cl;i<=cr;i++)ans[c[qc[i]].y]=a[l]; return; } for(int i=cl;i<=cr;i++)g[c[qc[i]].y]=0; int mid=(l+r)>>1,c0=0,c1=0;ll s0=0,s1=0; for(int i=cl,j=bl;i<=cr;i++){ for(;j<=br&&b[qb[j]].x<=c[qc[i]].x;j++){ if(b[qb[j]].y>mid)continue; if(b[qb[j]].t>0)c0++,s0+=b[qb[j]].x;else c1++,s1+=b[qb[j]].x; } ll t=(1LL*(c[qc[i]].x+1)*c0-s0)-(1LL*(c[qc[i]].x+1)*c1-s1); if(c[qc[i]].t>0)g[c[qc[i]].y]+=t;else g[c[qc[i]].y]-=t; } int L=0,R=0; for(int i=bl;i<=br;i++)if(b[qb[i]].y<=mid)ql[L++]=qb[i];else qr[R++]=qb[i]; for(int i=0;i<L;i++)qb[bl+i]=ql[i]; for(int i=0;i<R;i++)qb[bl+L+i]=qr[i]; int bm=bl+L-1; L=R=0; for(int i=cl;i<=cr;i++){ int j=c[qc[i]].y; if(f[j]<=g[j])ql[L++]=qc[i];else qr[R++]=qc[i]; } for(int i=cl;i<=cr;i++)if(c[qc[i]].t>0){ int j=c[qc[i]].y; if(f[j]>g[j])f[j]-=g[j]; } for(int i=0;i<L;i++)qc[cl+i]=ql[i]; for(int i=0;i<R;i++)qc[cl+L+i]=qr[i]; solve(l,mid,bl,bm,cl,cl+L-1),solve(mid+1,r,bm+1,br,cl+L,cr);}int main(){ scanf("%d%d%d",&i,&n,&m); for(i=1;i<=n;i++){ scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); a[i]=e[i][2]; } sort(a+1,a+n+1); for(i=1;i<=n;i++){ e[i][2]=lower(e[i][2]); b[++cb]=E(e[i][0],e[i][2],1); b[++cb]=E(e[i][1]+1,e[i][2],-1); } for(i=1;i<=m;i++){ scanf("%d%d%lld",&x,&y,&f[i]); c[++cc]=E(x-1,i,-1); c[++cc]=E(y,i,1); } sort(b+1,b+cb+1,cmp); sort(c+1,c+cc+1,cmp); for(i=1;i<=cb;i++)qb[i]=i; for(i=1;i<=cc;i++)qc[i]=i; solve(1,n,1,cb,1,cc); for(i=1;i<=m;i++)printf("%d\n",ans[i]); return 0;}
J. Restoring the Flows
设$x[i]$为第$i$条边的流量,对于每个节点根据流量平衡列出方程,那么一共有$m$个未知量,$n$个方程,那么答案就是这个矩阵的秩。
注意到任意时刻每个未知量只出现两次,并且系数一正一负,因此直接高斯消元的复杂度为$O(nm)$。
#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 )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int MAXN = 505 ;const int MAXM = 3005 ;int a[MAXN][MAXM] , n , m ;int gauss ( int n , int m ) { int r = 1 , c = 1 ; for ( ; r <= n && c <= m ; ) { int tmp = r ; for ( int i = r ; i <= n ; ++ i ) { if ( a[i][c] ) tmp = i ; } if ( tmp == r ) { ++ c ; continue ; } for ( int i = 1 ; i <= m ; ++ i ) { swap ( a[r][i] , a[tmp][i] ) ; } for ( int i = r + 1 ; i <= n ; ++ i ) if ( a[i][c] ) { for ( int j = c ; j <= m ; ++ j ) { a[i][j] += a[r][j] ; } } ++ r ; } return m - r + 1 ;}void solve () { for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 1 ; j <= m ; ++ j ) { a[i][j] = 0 ; } } for ( int i = 1 ; i <= m ; ++ i ) { int u , v ; scanf ( "%d%d" , &u , &v ) ; a[u][i] = 1 ; a[v][i] = -1 ; } printf ( "%d\n" , gauss ( n , m ) ) ;}int main () { while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ; return 0 ;}
XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus