1. 程式人生 > >data track capacitor 10.3模擬題 題解總結

data track capacitor 10.3模擬題 題解總結

 今天題目挺難的,第二題有坑,題目中輸入n,m,根所屬的節點後,還有個E (= n-m)的輸入,導致全場第二題爆零。

就得了第一題100分,第三題暴力深搜都錯了。。。我實在太弱了。。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 第一題。

題意中電容公式其實就是咱的電阻串並聯的公式,只是反著來(串是並的效果,並是串的效果)。

實際上如果當前拼成的是 c/d 那麼並聯相當於變成(c+d)/d,串聯相當於變成(c+d) /c。

相當於一個輾轉相除法,就看除了多少下,多少下就是多少個電阻。

(dalao們不需要的)程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 999999999;
int T;
ll a,b;
ll ans = 0;

ll Gcd(ll a,ll b)
{
	return b == 0 ? a : Gcd(b,a%b);
}
int main()
{
//	freopen("capacitor.in","r",stdin);
//	freopen("capacitor.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);	
	cin >> T;
	while(T--)
	{
		cin >> a >> b;
		ans = 0;
		ll gcd = Gcd(a,b);
		a /= gcd,b /= gcd;
		while(a != 0 && b != 0)
		{
			if(a > b)
			{
				ans += a/b;
				a %= b;
			}
			else
			{
				swap(a,b);
				ans += a/b;
				a %= b;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

題目大意
要求維護一個森林,支援連邊操作和查詢兩點  LCA  操作。

有個大坑,上面說的,除此以外還有個很陰險的坑:連邊會破壞樹的結構,會換根!

dalao看到一句LCT就A了,但咱是蒟蒻。。

於是咱用noip的 按秩合併(啟發式合併)並查集+Lca倍增 複雜度O(nlog^2)可以過。這為線上做法,要慢一點,但由於本蒟蒻考場上寫的跟這種很相似,下來根據講解稍微改了一下就過了。

另一種為離線操作,先掃一遍提問,把應該連的邊都連上,任找一個點為根建立  LCA  倍增陣列。然後從頭到尾處理每次提問:

對於操作  1,用並查集維護每個點當前所在的樹的編號,和這棵樹現在“真正”的根是誰,

對於操作  2,我們要求出當  LCA  倍增陣列是以某個點(VROOT)為根建立的時候,兩點(u, v)在以某個點(root)為根的意義下的  LCA。求出  u, v,root  兩兩之間的  LCA,找出其中在以  VROOT  為根時,深度最大的那個  LCA(討論  u,v,root  三點在以  VROOT  為根時的相對位置關係,不(hen)難證明其正確性(我不會))。
時間複雜度 O(Q log N)  要快一點。

於是 按秩合併+LCA倍增 程式碼附上:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define in(x) read(x)
#define out(x) print(x)
const int MAXN = 1e5 + 5;
int f[MAXN][21];
int dep[MAXN],rt[MAXN],root[MAXN];
int size[MAXN];
int head[MAXN*2],cnt = 0;
void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
void print(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
struct node
{
	int next,to;
}e[MAXN*2];
void add(int u,int v)
{
	e[++cnt].next = head[u],e[cnt].to = v,head[u] = cnt;
	e[++cnt].next = head[v],e[cnt].to = u,head[v] = cnt;
}
int n,m,q,E;
void rebuild(int x,int fr)
{
	for(int i = 1;i <= 20;i++) f[x][i] = f[f[x][i-1]][i-1];
	for(int i = head[x];i;i = e[i].next)
	{
		int to = e[i].to;
		if(to == fr) continue;
		dep[to] = dep[x] + 1;
		f[to][0] = x;
		rebuild(to,x);
	}
}

void dfs(int x,int fr)
{
	f[x][0] = fr;
	for(int i = head[x];i;i = e[i].next)
	{
		int to = e[i].to;
		if(to == fr) continue;
		dep[to] = dep[x] + 1;
		dfs(to,x);
		size[x] += size[to];
	}
}

int find(int x)
{
	for(int i = 20;i >= 0;i--) if(f[x][i]) x = f[x][i];
	return x;
}


int Lca(int x,int y)
{
	if(dep[x] < dep[y]) swap(x,y);
	for(int i = 20;i >= 0;i--)
		if(dep[x] - (1 << i) >= dep[y])
			x = f[x][i];
	if(x == y) return x;
	for(int i = 20;i >= 0;i--)
		if(f[x][i] != f[y][i])
			x = f[x][i],y = f[y][i];
	return f[x][0];
}

int main()
{
	in(n); in(m);
	for(int i = 1;i <= m;i++) in(rt[i]);
	read(E);
	for(int i = 1;i <= E;i++)
	{
		int x,y;
		in(x); in(y);
		add(x,y);
	}
	for(int i = 1;i <= n;i++) size[i] = 1;
	for(int i = 1;i <= m;i++)
	{
		dep[rt[i]] = 1;
		dfs(rt[i],0);
	}
	for(int j = 1;j <= 20;j++)
		for(int i = 1;i <= n;i++)
			f[i][j] = f[f[i][j-1]][j-1];
	for(int i = 1;i <= n;i++)
	{
		int o = find(i);
		if(o) root[i] = o;
		else root[i] = i;
	}
	in(q);
	for(int i = 1;i <= q;i++)
	{
		int tmp,u,v;
		in(tmp); in(u); in(v);
		if(tmp == 1)
		{
			int x = find(u),y = find(v);
			if(x == y) continue;
			if(size[x] > size[y])
			{
				f[v][0] = u;
				size[x] += size[y];
				dep[v] = dep[u] + 1;
				root[y] = root[x];
				add(u,v);
				rebuild(v,u);
			}
			else
			{
				f[u][0] = v;
				size[y] += size[x];
				dep[u] = dep[v] + 1;
				root[y] = root[x];
				add(u,v);
				rebuild(u,v);
			}
		}
		else{
			if(find(u) != find(v))
			{
				cout << "orzorz" << endl;
				continue;
			}
			int x = find(u);
			int o = Lca(u,v),t = Lca(root[x],v);
			if(dep[o] < dep[t]) o = t;
			t = Lca(root[x],u);
			if(dep[o] < dep[t]) o = t;
			out(o);
			putchar('\n');
		}
	}
	return 0;
}

暴力大法好,蒟蒻打不了。

考試時看出是DP,於是使勁寫,,,然後沒寫出來。

我一直認為f[200][200][200]會爆空間,,,發現自己計算時多乘了個100....變成1e8的bite,,,果斷思考滾動陣列,然後就沒寫出來。。(如果哪位大佬看出來確實可以用滾動陣列(就是那個i 當前秒數)確實可以的話請評論告訴我,謝謝!)

正解就是f[i][j][k]三維。。。

dp[i][j][k]表示到第 i 秒後當前高度是 j 且匹配了 k 位的方案數。

那麼 dp[i][j][k]可以轉移:
if(s[k] == 'U'){
       (dp[i + 1][j + 1][k + 1] += dp[i][j][k]) %= mod;
       if(j) (dp[i + 1][j - 1][fail[k][1]] += dp[i][j][k]) %= mod;}
if(s[k] == 'D'){
       (dp[i + 1][j + 1][fail[k][0]] += dp[i][j][k]) %= mod;
       if(j) (dp[i + 1][j - 1][k + 1] += dp[i][j][k]) %= mod;}
特別的,我們記 dp [i][j][slen]為到第 i 秒後當前高度是 j 且匹配成功的所有方案數。
那麼      (dp[i + 1][j + 1][slen] += dp[i][j][slen]) %= mod;
               if(j) (dp[i + 1][j - 1][slen] += dp[i][j][slen]) %= mod;
答案就是 dp[n][0][slen]

其中fail[k][0/1]代表第k位未成功匹配(就是那個'U'和'D'不能連成能令貓摔跤的那個連續字串)後可以從哪裡再次開始匹配。

後面一維 1 代表在'U'處沒能匹配上,0 代表在'D'處沒能匹配上。、

這個fail[k][0/1]可以kmp預處理出來,也很快。由於字串很短 直接暴力處理也行。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 205;
const int MOD = 1000000007;
int ans = 0;
string s;
int n,len;
int f[MAXN][MAXN][MAXN],fail[MAXN][2],next[MAXN];
void init()
{
	int j = 0;
	next[0] = next[1] = 0;
	for(int i = 1;i < len;i++)
	{
		while(j > 0 && s[i] != s[j]) j = next[j];
		if(s[i] == s[j]) j++;
		next[i+1] = j;
	}
	fail[0][s[0] == 'U'] = 1;
	for(int i = 1;i <= len;i++)
	{
		int pos = i;
		while(pos && s[pos] != 'U') pos = next[pos];
		fail[i][1] = pos+1;
		if(pos == 0 && s[0] == 'D') fail[i][1] = 0;
		pos = i;
		while(pos && s[pos] != 'D') pos = next[pos];
		fail[i][0] = pos+1;
		if(pos == 0 && s[0] == 'U') fail[i][0] = 0;
	}
}

int main()
{
//	freopen("track.in","r",stdin);
//	freopen("track.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);	
	cin >> n >> s;
	len = s.size();
	if(n & 1) 
	{
		cout << 0 << endl;
		return 0;
	}
	init();
	f[0][0][0] = 1;
	for(int i = 0;i < n;i++)
	{
		for(int j = 0;j <= min(i,n-i);j++)
		{
			for(int k = 0;k < len;k++)
			{
				if(s[k] == 'U')
				{
					f[i+1][j+1][k+1] = (f[i+1][j+1][k+1] + f[i][j][k]) % MOD;
					if(j) f[i+1][j-1][fail[k][0]] = (f[i+1][j-1][fail[k][0]] + f[i][j][k]) % MOD;
				}
				else
				{
					f[i+1][j+1][fail[k][1]] = (f[i+1][j+1][fail[k][1]] + f[i][j][k]) % MOD;
					if(j) f[i+1][j-1][k+1] = (f[i+1][j-1][k+1] + f[i][j][k]) % MOD;
				}
			}
			f[i+1][j+1][len] = (f[i+1][j+1][len] + f[i][j][len]) % MOD;
			if(j) f[i+1][j-1][len] = (f[i+1][j-1][len] + f[i][j][len]) % MOD;
		}
	}
	cout << f[n][0][len] % MOD;
	return 0;
}