T1递推O(N^2),也可以数学公式算组合数O(n),T2类似之前的一道题目星座,把n遍dfs变成1遍,O(n),T3基环外向树+期望+DP+数学,省选入门题
T1
Solution
这道题目把图画出来理解一下那个一一对应就可以了。
我感觉题解有点小问题,应该是从第一个经过的那个非法的点开始,之后的每一个格子都沿y=x+1翻,这样才对。
CODE
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
long long f[2005][2005];
int n;
int main()
{
cin>>n;
for (int i=1;i<=n;i++) f[1][i]=1;
for (int i=2;i<=n;i++)
for (int j=1;j<=n;j++)
if (j<i) f[i][j]=0;
else f[i][j]=(f[i-1][j]+f[i][j-1])%MOD;
cout<<f[n][n];
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define MAXN 500001
#define MOD 1000000007
ll pw(ll x,ll y,ll mod) {ll ans=1;for(;y;y>>=1) {if(y&1)ans=ans*x%mod;x=x*x%mod;}return ans;}
ll rev(ll x) {return pw(x, MOD-2, MOD);}
ll fact[MAXN];
ll C(ll n, ll m) {
if (m<0 || m>n) return 0;
return fact[n] * rev(fact[m]*fact[n-m] % MOD) % MOD;
}
ll F(ll n, ll m) {
return C(n+m,m);
}
int main() {
fact[0] = 1;
for (int i=1;i!=MAXN;++i)
fact[i] = fact[i-1]*i % MOD;
int n; scanf("%d",&n);
--n;
printf("%d\n",(F(n,n)-F(n-1,n+1)+MOD)%MOD);
return 0;
}
T2
Solution
PS:有句mmp我一定要将,这道题目我给dp_f,dp_g memset的时候sizeof(f),然后就光荣的WA了,关键是把数组开大1倍后就A了,最后hk大佬不谢的帮我调试+yh大佬的一语道破,竟然找出了这个错误,感谢两位大佬!!
T3
Solution
还没写过,之后来填坑。
先写一些吧。首先这道题目要抽象成一个基环外向树森林
为什么呢?根据题目特性我们知道在原来的图中一个点必定有且只能出去到一个固定的点,却可以有其他几个点进入,题意是倒着走,将所有的边反向之后就成了一个点可以出去好几个点,但有且仅有一条入边,这样就否决了基环内向树的可能(因为向环内走的话就会有节点有多余一个的入点)。
接着我们要计算期望,期望=概率*贡献。
我们设f[i]为树上的节点i的期望代价,设cnt[i]为i的出边个数,c[i]为i的代价,则
f[u]=c[u]+∑v为u的树上子节点f[v]cnt[u]+1
再看环上的期望,设g[p]为p的期望,q为p的后继结点g[p]=c[p]+g[q]cnt[p]+1+f[p]∗cnt[p]cnt[p]+1
前者为在环上走的代价,后者为有cnt[p]cnt[p]+1的概率向树上走,再乘以代价f[p]即可,但是式子中还有g[q]一项,我们绕着整个圈写出圈中点数x个方程,再代入求解即可。
100%:虽然代价会变,但整个图的结构不变,所以概率不变,可以先预处理出每个点的概率,在用线段树维护代价即可(我会说我也不会吗?)
PS:myx大佬说这题目是基环外向树中的简单题,因为结构不变……