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

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/82933081
今日推荐