首页 > 其他分享 >P7618 [COCI2011-2012#2] FUNKCIJA 题解

P7618 [COCI2011-2012#2] FUNKCIJA 题解

时间:2024-01-22 22:44:42浏览次数:16  
标签:int 题解 LL add 循环 P7618 str FUNKCIJA 节点

看起来比较复杂,但实际上是一个树上 dp 的模型。

因为每一重循环都最多有一个依赖,可以转化为树上的父子关系,于是就形成了一个森林。

对于非叶子节点,设 \(f_{u,i}\) 表示第 \(u\) 循环变量的值是 \(i\) 时所有直接或间接依赖于它的循环变量(即以它为根的子树除开它的部分)循环次数,对非根节点设 \(g_{u,i}\) 表示当第 \(u\) 个变量依赖的循环变量值为 \(i\) 时它和所有直接或间接依赖于它的循环变量(即以它为根的子树)循环次数。

对于非叶子节点,可以发现一个节点的子节点的子树是不互相影响的,也就是说交换子树之间循环的内外位置是不会影响答案的,根据乘法原理,\(f_{u,i}=\prod g_{v,i}\),其中 \(v\) 是 \(u\) 的子节点。

对于非根节点,父亲节点循环变量的取值会限制这个变量的取值范围,所以 \(g\) 应该是 \(f\) 的一个区间和。具体地,如果父亲节点限制了取值的上界,则当 \(i<x_u\) 时,\(g_{u,i}=0\),当 \(i\ge x_u\) 时,\(g_{u,i}=\sum_{j=x_u}^i f_{u,j}\);如果父亲节点限制了取值的下界,则当 \(i>y_u\) 时,\(g_{u,i}=0\),当 \(i\le y_u\) 时,\(g_{u,i}=\sum_{j=i}^{y_u}f_{u,i}\),可以用前缀和优化。

对每棵树处理完 dp 数组之后,考虑计算答案。可以发现对于所有子树之间的循环内外关系也是可以交换的,所以答案就是所有根节点对答案贡献的乘积,如果根节点 \(u\) 有儿子节点,就让答案乘上 \(\sum_{i=x_u}^{y_u}f_{u,i}\),如果没有儿子节点,那这就是一层没有限制也不限制其他变量取值的循环了,就让答案乘上 \(y_u-x_u+1\)。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 30, M = 1e5 + 5, P = 1e9 + 7;

int n, m = 1e5;
char str[N];
int x[N], y[N], fa[N], op[N];
int la[N], ne[N], en[N], idx;
bool st[N];
LL f[N][M], s[N][M];
LL res;

void add(int a, int b)
{
	ne[ ++ idx] = la[a];
	la[a] = idx;
	en[idx] = b;
}

void add(LL &x, LL y)
{
	x += y;
	if(x >= P) x -= P;
}

void dfs(int u)
{
	st[u] = true;
	if(!la[u])
	{
		if(op[u] == 1)
			for(int j = 1; j <= m; j ++ ) f[u][j] = max(y[u] - j + 1, 0);
		else
			for(int j = 1; j <= m; j ++ ) f[u][j] = max(j - x[u] + 1, 0);
		for(int j = 1; j <= m; j ++ ) s[u][j] = s[u][j - 1], add(s[u][j], f[u][j]);
	}
	else
	{
		for(int i = 1; i <= m; i ++ ) f[u][i] = 1;
		for(int i = la[u]; i; i = ne[i])
		{
			int v = en[i];
			dfs(v);
			for(int j = 1; j <= m; j ++ ) f[u][j] = f[u][j] * f[v][j] % P;
			for(int j = 1; j <= m; j ++ ) s[u][j] = s[u][j - 1], add(s[u][j], f[u][j]);
		}
		if(fa[u])
		{
			if(op[u] == 1)
				for(int j = 1; j <= m; j ++ )
				{
					if(j > y[u]) f[u][j] = 0;
					else f[u][j] = s[u][y[u]], add(f[u][j], P - s[u][j - 1]);
				}
			else
				for(int j = 1; j <= m; j ++ )
				{
					if(j < x[u]) f[u][j] = 0;
					else f[u][j] = s[u][j], add(f[u][j], P - s[u][x[u] - 1]);
				}
			for(int j = 1; j <= m; j ++ ) s[u][j] = s[u][j - 1], add(s[u][j], f[u][j]);
		}
	}
}

int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++ )
	{
		scanf("%s", str);
		if(str[0] > '9')
		{
			fa[i] = str[0] - 'a' + 1;
			op[i] = 1;
			add(fa[i], i);
		}
		else
			for(int j = 0; str[j]; j ++ ) x[i] = x[i] * 10 + str[j] - 48;
		scanf("%s", str);
		if(str[0] > '9')
		{
			fa[i] = str[0] - 'a' + 1;
			op[i] = 2;
			add(fa[i], i);
		}
		else
			for(int j = 0; str[j]; j ++ ) y[i] = y[i] * 10 + str[j] - 48;
	}
	
	res = 1;
	for(int i = 1; i <= n; i ++ )
		if(!st[i])
		{
			if(la[i])
			{
				dfs(i);
				res = res * (s[i][y[i]] - s[i][x[i] - 1] + P) % P;
			}
			else res = res * (y[i] - x[i] + 1) % P;
		}
	
	printf("%lld\n", res);
	return 0;
}

标签:int,题解,LL,add,循环,P7618,str,FUNKCIJA,节点
From: https://www.cnblogs.com/recollect-the-past/p/17981268

相关文章

  • 题解-[ABC288D] Range Add Query
    题目:[ABC288D]RangeAddQuery-洛谷|计算机科学教育新生态(luogu.com.cn) 大意:一些数,选一个区间A(L~R),并再选一个区间B(长度k),这个区间B的每个数加减(加负数=减一个数)一个数,最终使得区间A全部数为0举个例(样例)0.   3-11-2201.  0-4-2-220 (-3)2.  ......
  • 2024 蓝桥杯模拟赛 1 (div1) 题解
    A.把字符串小写转换成大写即可#include<bits/stdc++.h>usingnamespacestd;voidsolve(){strings;cin>>s;for(inti=0;i<s.size();i++){if(s[i]>='a'&&s[i]<='z'){s[i]=(char)(s[i]-'a......
  • 2024 省选联测部分题解
    目录目录R15T1树V图R15T2矩阵缺失题目:R15T3.R15T1树V图原题:SNOI2024D1T1.注意到答案肯定是形如每个连通块选一个点组成,把连通块缩起来后令\(dp_{u,x}\)表示连通块\(u\)选\(x\)的方案数,每次合并子树转移即可.因为只有\(n^2\)个合法点对所以时间复杂度......
  • R语言包安装失败常见问题解决
    更改或指定镜像源出现这个问题很有可能是你现在用的镜像中未纳入这个包,一是可以多换个源试试。如:install.packages('package-name',repos='http://cran.us.r-project.org')或,在Rstudio中可以:或,命令行可直接指定Rstudio:install.packages('package_name',dependencies=TRUE......
  • 【问题解决】Kafka报错 Bootstrap broker x.x.x.x:9092 (id: -1 rack: null) disconne
    【问题解决】Kafka报错Bootstrapbrokerx.x.x.x:9092(id:-1rack:null)disconnected和服务器连接已经断开。可能kafka服务器停止问题复现近日针对某一客户需求开发了一个需要使用Kafka的功能,功能是什么暂且不论,在本地虚机的Kafka连接一切正常遂放到测试服务器上验证功......
  • Kafka【问题 02】KafkaTemplate 报错 Bootstrap broker localhost:9092 (id: -1 rack:
    Kafka【问题02】KafkaTemplate报错Bootstrapbrokerlocalhost:9092(id:-1rack:null)disconnected问题解决1.报错信息主要的报错信息:Connectiontonode-1(localhost/127.0.0.1:9092)couldnotbeestablished.Brokermaynotbeavailable.和Bootstrapbrok......
  • CF1920E 题解
    CF1920E被这种题卡了,脸都不要了。仔细读题,发现序列可以分成两部分(\(0\)和\(1\))来考虑。在合法序列中,对于一个\(1\),它产生的子串贡献一定是(假设与上一个\(1\)之间有\(x\)个\(0\),与下一个\(1\)之间有\(y\)个\(0\)):\[(x+1)(y+1)\]如果去DP这\(n\)个\(1\),易得转......
  • CF455D Serega and Fun 题解
    题目链接:CF或者洛谷本题是可以用平衡树去做的,具体的为每个\(k\)开一棵平衡树去维护相对位置,而这种移动操作用平衡树维护又是很容易做到的,这种做法是双\(log\)。在\(1e5\)的数据下,我们来说说好写的分块该如何去写。黑色的代表一个块,考虑暴力修改情况,假如原来的数字为\([1......
  • 决斗 题解
    决斗题解赛题来自OIFHA第四场模拟赛。原题展现青蛙哥与名侦探柯南正在进行一场对决。他们两个人每人有\(n\)张牌,每张牌有一个点数。并且在接下来的\(n\)个回合中每回合青蛙哥与名侦探柯南两人会各自打出一张牌。每回合裁判会检查,打出的牌点数更高的一方获胜从而得到......
  • UVA10295 Hay Points 题解
    题目大意:给你\(n\)个单词,每一个单词的值为\(v_i\),让你求出在一个文章段落里的出现过的单词的值之和。思路:可以用STL库中的map来存储一个单词的值,最后在处理的时候可以直接累加。附上你们最期待的代码:#include<bits/stdc++.h>usingnamespacestd;map<string,int......