1. 程式人生 > 實用技巧 >2020-12-1 題目題解

2020-12-1 題目題解

「JOISC 2014 Day3」電壓

題目傳送門

Description

JOI 公司的某個實驗室中有著複雜的電路。電路由 \(N\) 個節點和 \(M\) 根細長的電阻組成。節點編號為 \(1\sim N\)
每個節點可設定為兩種電平之一:高電平或者低電平。每個電阻連線兩個節點,只有一端是高電平,另一端是低電平的電阻才會有電流流過。兩端都是高電平或者低電平的電阻不會有電流流過。
試求:有多少個電阻,可以通過調節各節點的電壓,使得「沒有電流流經該電阻,且其他 \(M-1\) 根電阻中都有電流流過」。
\(N\le 10^5,M\le 2\times 10^5\)

Solution

不難看出,一條邊滿足條件的情況當且僅當奇環都包含這條邊且偶環都不包含這條邊。然後這個可以直接 dfs 樹上差分。

時間複雜度 \(\Theta(n+m)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,m;

struct edge{
	int v,nxt;
}e[MAXN << 2];

int toop = 1,head[MAXN];

void Add_Edge (int u,int v){
	e[++ toop] = edge {v,head[u]},head[u] = toop;
	e[++ toop] = edge {u,head[v]},head[v] = toop;
}

bool rt[MAXN],vis[MAXN];
int ocnt,dep[MAXN],ores[MAXN],eres[MAXN];

void dfs (int u,int fa){
	vis[u] = 1;
	for (Int i = head[u];i;i = e[i].nxt) if (i ^ fa ^ 1){
		int v = e[i].v;
		if (!vis[v]) dep[v] = dep[u] + 1,dfs (v,i),ores[u] += ores[v],eres[u] += eres[v];
		else if (dep[v] < dep[u]){
			if (dep[u] - dep[v] & 1) eres[u] ++,eres[v] --;
			else ores[u] ++,ores[v] --,ocnt ++;
		}
	}
}

signed main(){
	read (n,m);
	for (Int i = 1,u,v;i <= m;++ i) read (u,v),Add_Edge (u,v);
	for (Int i = 1;i <= n;++ i) if (!vis[i]) rt[i] = 1,dfs (i,0); 
	int ans = ocnt == 1;for (Int i = 1;i <= n;++ i) if (!rt[i] && !eres[i] && ores[i] == ocnt) ans ++;
	write (ans),putchar ('\n');
	return 0;
}

導彈防禦塔

題目傳送門

Solution

可以二分答案,然後把每一個防禦塔拆開跑二分圖匹配。

時間複雜度玄學。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 55

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

double t1,t2;
vector <int> G[MAXN * MAXN];
int n,m,tot,v,my[MAXN * MAXN];

struct node{
	int id;double pret;
}ver[MAXN * MAXN];

void prepare (){
	for (Int i = 1;i <= n;++ i)
		for (Int j = 1;j <= m;++ j) 
			ver[++ tot] = node {i,(j - 1) * (t1 + t2) + t1};
}

int sqr (int x){return x * x;}
struct Point{
	int x,y;
	void getit (){read (x,y);}
	friend double dist (Point a,Point b){return sqrt (sqr (a.x - b.x) + sqr (a.y - b.y));}
}dat[MAXN],ene[MAXN];

bool vis[MAXN * MAXN];

bool dfs (int u){
	for (Int v : G[u]) if (!vis[v]){
		vis[v] = 1;
		if (my[v] == -1 || dfs (my[v])){
			my[v] = u;
			return 1;
		}
	}
	return 0;
}

bool check (double s){
	for (Int i = 1;i <= m;++ i) G[i].clear();
	memset (my,-1,sizeof (my));
	for (Int i = 1;i <= m;++ i)
		for (Int j = 1;j <= tot;++ j)
			if (ver[j].pret + dist (ene[i],dat[ver[j].id]) / v <= s)
				G[i].push_back (j);
	int ans = 0;
	for (Int i = 1;i <= m;++ i) memset (vis,0,sizeof (vis)),ans += dfs (i);
	return ans == m;
}

signed main(){
	read (n,m),scanf ("%lf%lf",&t1,&t2),t1 /= 60,read (v);prepare ();
	for (Int i = 1;i <= m;++ i) ene[i].getit();
	for (Int i = 1;i <= n;++ i) dat[i].getit();
	double l = 0,r = 1e9,ans = -1;
	while (r - l > 1e-7){
		double mid = (l + r) / 2;
		if (check (mid)) ans = mid,r = mid;
		else l = mid;
	}
	printf ("%.6f\n",ans);
	return 0;
}