【GDOI2018模拟7.7】暴力大神hxx 树形dp
2017-07-07 20:55
323 查看
题意:给你n个嵌套for语句,然后从第二个开始每一个循环的起点或者是终点是变量,问你会循环多少次。
这是一道好题。
手玩一下可以很容易发现,上下之间有可以递推的关系,但是直接递推会炸,所以需要dp。
假设语句是这样的:
for i 1 100
for j i 100
for k j 100
我们可以手玩一下发现:
只有一条语句:
1-100
两条语句:
(1-100,2-100,3-100…….100-100) 相邻之间差为1.
我们并不需要直接计算出量级,只要无脑往上用乘法原理乘乘乘就好了。
可以发现,第n条语句和第n-1条直接相关,可以通过他推出来,但是他也和第n-2…1条语句间接有关,所以,可以联想到树形dp(比较关键的一步,其实挺好想,模型很明显了)
然后,设f[x][i]以x为根的子树的答案,或者说:把变量x取值为i时的计算结果
那么根据乘法原理直接把所有子树乘起来就好了,但是还是会T,用前缀和优化一下(第二个比较关键的地方),具体看代码。
转化模型和处理方法都十分经典。
这是一道好题。
手玩一下可以很容易发现,上下之间有可以递推的关系,但是直接递推会炸,所以需要dp。
假设语句是这样的:
for i 1 100
for j i 100
for k j 100
我们可以手玩一下发现:
只有一条语句:
1-100
两条语句:
(1-100,2-100,3-100…….100-100) 相邻之间差为1.
三条语句(这里对齐一下让大家更好理解): (1-100,2-100,3-100.......100-100) (2-100,3-100.......100-100) (3-100.......100-100) .... 注意从这里开始差变得不规则了,我把这种不规则的差称之为量级。 可以发现的是,量级的大小明显和嵌套语句的个数有一个公式可以互相转换,那么用相关的数学知识应该是可以推出的(我不会QAQ),但是对于一个OIER,做到这一步就够了。
我们并不需要直接计算出量级,只要无脑往上用乘法原理乘乘乘就好了。
可以发现,第n条语句和第n-1条直接相关,可以通过他推出来,但是他也和第n-2…1条语句间接有关,所以,可以联想到树形dp(比较关键的一步,其实挺好想,模型很明显了)
然后,设f[x][i]以x为根的子树的答案,或者说:把变量x取值为i时的计算结果
那么根据乘法原理直接把所有子树乘起来就好了,但是还是会T,用前缀和优化一下(第二个比较关键的地方),具体看代码。
转化模型和处理方法都十分经典。
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--); using namespace std; typedef long long ll; const int mo=12015858; const int N=1e5+5; char x ,y ,n; int l ,r ,f[27] ; int tot; bool vis ; int head ,go ,next ,val ; inline void add(int x,int y) { go[++tot]=y; next[tot]=head[x]; head[x]=tot; } inline void dfs(int x) { for(int i=head[x];i;i=next[i]) { int v=go[i]; dfs(v); } fo(i,1,100000) { f[x][i]=1; for(int j=head[x];j;j=next[j]) { int v=go[j]; if (!l[v]&&i>r[v]||!r[v]&&i<l[v]) { f[x][i]=0; break; } if (!r[v])f[x][i]=1ll*f[x][i]*(f[v][i]-f[v][l[v]-1])%mo; else f[x][i]=1ll*f[x][i]*(f[v][r[v]]-f[v][i-1])%mo; } f[x][i]=(f[x][i]+mo)%mo; } fo(i,1,100000)f[x][i]=(f[x][i]+f[x][i-1])%mo; } int main() { scanf("%d",&n); fo(i,1,n) { char ch[7]; scanf("%s",ch); int len=strlen(ch); if (ch[0]<='z'&&ch[0]>='a') { add(ch[0]-'a'+1,i); vis[i]=1; } else fo(j,0,len-1)l[i]=l[i]*10+ch[j]-'0'; scanf("%s",ch); len=strlen(ch); if (ch[0]<='z'&&ch[0]>='a') { add(ch[0]-'a'+1,i); vis[i]=1; } else fo(j,0,len-1)r[i]=r[i]*10+ch[j]-'0'; } ll ans=1; fo(i,1,n)if (!vis[i]) { dfs(i); ans=ans*1ll*(f[i][r[i]]-f[i][l[i]-1])%mo; } printf("%lld\n",(ans+mo)%mo); }
相关文章推荐
- JZOJ 5207【GDOI2018模拟7.7】暴力大神hxx
- jzoj5220 【GDOI2018模拟7.10】C (双序列dp)
- 【JZOJ5272】【GDOI2018模拟】神奇的重复序列(DP,性质题)
- JZOJ5233 【GDOI模拟8.5】概率博弈 树形dp
- 【GDOI2018模拟7.7】寻找天哥
- jzoj3583 [GDOI2014模拟] 小A的树 树形dp
- 【JZOJ5262】【GDOI2018模拟8.12】树(DP,性质题)
- 【jzoj5238】【GDOI2018模拟8.7】【的士碰撞】
- (noip 模拟 染色)<树形DP>
- 2018.02.08【GDOI2018】模拟C组
- (vijos 1892 noip 模拟 tree)<树形DP求树的最大匹配及方案数>
- JZOJ5213. 【GDOI2018模拟7.9】期末考试
- 【GDOI2018模拟7.8】矩阵
- 【GDOI2018模拟7.10】C
- 【JZOJ 5215】【GDOI2018模拟7.9】组合数问题
- 【GDOI2018模拟7.14】小奇的糖果 树状数组+扫描线
- 【JZOJ5250】【GDOI2018模拟】质数(数论)
- [jzoj]3482. 【NOIP2013模拟10.23】轮舞前夕(经典树形DP)
- 【JZOJ5272】【GDOI2018模拟8.14】神奇的重复序列
- 【JZOJ5270】【GDOI2018模拟】神奇的矩阵(二维线段树)