XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus

时间:2021-07-23 14:34:35

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 ;
}