用 f[i][j] 表示 i 一共获得了 j 次“机会”的概率。
注意这里的“机会”,是指有多少轮中,它前面的所有卡牌,要么在之前的轮中发动过,要么在这一轮中因为运气没有发动。
这里的“机会”不与自己有没有发动相关。所以就算在之前某轮中发动过,这一轮轮到它的时候贡献依然要增加。
于是有 f[i][j]=f[i−1][j+1]⋅(1−(1−p[i−1])j)+f[i−1][j]⋅(1−p[i−1])j
ans=∑ni=1∑rj=1f[i][j]⋅d[i]⋅(1−(1−p[i])j)
#include
typedef long long LL;
#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)
template <typename Tp> void in(Tp &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
const int MAXN = 230, MAXR = 140;
int T, n, r, d[MAXN];
double p[MAXN], f[MAXN][MAXR];
double power(double x, int y)
{
double ret = 1;
while (y) {
if (y & 1) ret *= x;
x *= x;
y >>= 1;
}
return ret;
}
int main()
{
freopen("arthur.in", "r", stdin);
freopen("arthur.out", "w", stdout);
in(T);
while (T--) {
in(n); in(r);
FOR(i, 1, n) {
scanf("%lf", &p[i]); in(d[i]);
}
memset(f, 0, sizeof f);
f[1][r] = 1;
FOR(i, 2, n) FOR(j, 1, r) {
f[i][j] = 0;
f[i][j] += f[i - 1][j + 1] * (1 - power(1 - p[i - 1], j + 1));
f[i][j] += f[i - 1][j] * power(1 - p[i - 1], j);
}
double ans = 0;
FOR(i, 1, n) FOR(j, 1, r) {
ans += f[i][j] * (1 - power(1 - p[i], j)) * d[i];
}
printf("%.10lf\n", ans);
}
return 0;
}
首先,我们求出每个点的dfs序。
然后对于一条x<–>y的路径,如果有路径包含它,那么有
如果 lca(x,y)=xory ,那么只需要这条路径的一个端点在深度大的点的子树中,另一个端点不在“深度小的点往深度大的点的方向上的第一个点”的子树中即可。
否则,那么只需要这条路径的两个端点分别在 x 和 y 的子树中即可。
我们令这条包含x<–>y的路径的两个端点中dfs序小的点为 a ,dfs序大的点为 b 。
对于上面两种情况中的任意一种情况,这种情况中 a 和 b 所在的子树互不相交,为两个不相交的dfs序区间(不在子树中的情况我们可以转化为在它的补集的区间的情况)。
于是我们就把问题转化为了,每个盘子对应一对(或两对,因为有“不在子树”)区间,然后对于每个水果的两个点,两个区间分别包含其两个点的盘子中,权值第 k 小的。
我们可以把一维转化成 x 坐标,另一维转化成 y 坐标,于是问题就转化为了包含一个点的矩形中第 k 小的。
于是可以用扫描线+树状数组套主席树解决。
#include
using std::map;
typedef long long LL;
#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <typename Tp> void in(Tp &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
const int MAXN = 100010;
const int appear = 0, disappear = 2, query = 1;
int n, p, q, ev_tot;
int cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1];
int INDEX, dfn[MAXN], ed[MAXN], depth[MAXN];
int anc[MAXN][18];
int ans[MAXN];
map<int, int>M; int M_point, to[MAXN << 3];
struct Event {
int type, num;
int time, l, r, w;
} ev[MAXN << 3];
namespace segment_tree
{
const int MAXS = MAXN * 250;
int seg_tot = 0, rot[MAXN], sz[MAXS], ch[MAXS][2];
int should_remove[250], should_add[250];
void build(int &now, int l, int r)
{
now = ++seg_tot;
if (l == r) return;
int mid = (l + r) >> 1;
build(ch[now][0], l, mid);
build(ch[now][1], mid + 1, r);
}
void initialize()
{
build(rot[0], 1, M_point);
FOR(i, 1, n) rot[i] = rot[0];
}
void push(int &now, int l, int r, int x, int modi)
{
int tmp = now;
now = ++seg_tot;
sz[now] = sz[tmp];
ch[now][0] = ch[tmp][0];
ch[now][1] = ch[tmp][1];
sz[now] += modi;
if (l == r) return;
int mid = (l + r) >> 1;
if (x <= mid) push(ch[now][0], l, mid, x, modi);
else push(ch[now][1], mid + 1, r, x, modi);
}
void getdown(int &ret, bool t)
{
ret = 0;
FOR(i, 1, should_add[0]) ret += sz[ch[should_add[i]][t]];
FOR(i, 1, should_remove[0]) ret -= sz[ch[should_remove[i]][t]];
}
void godown(bool t)
{
FOR(i, 1, should_add[0]) should_add[i] = ch[should_add[i]][t];
FOR(i, 1, should_remove[0]) should_remove[i] = ch[should_remove[i]][t];
}
void _query(int w, int l, int r, int num)
{
if (l == r) {
ans[num] = l;
return;
}
int ldata; getdown(ldata, 0);
int mid = (l + r) >> 1;
if (ldata >= w) {godown(0); _query(w, l, mid, num);}
else {godown(1); _query(w - ldata, mid + 1, r, num);}
}
void insert(int l, int r, int w)
{
if (l > r) {
debug("WA");
} //This line is for gdb
while (l <= n) {
push(rot[l], 1, M_point, w, 1);
l += l & -l;
}
r++;
while (r <= n) {
push(rot[r], 1, M_point, w, -1);
r += r & -r;
}
}
void remove(int l, int r, int w)
{
while (l <= n) {
push(rot[l], 1, M_point, w, -1);
l += l & -l;
}
r++;
while (r <= n) {
push(rot[r], 1, M_point, w, 1);
r += r & -r;
}
}
void query(int l, int r, int w, int num)
{
l--;
should_remove[0] = should_add[0] = 0;
while (l) {
should_remove[++should_remove[0]] = rot[l];
l -= l & -l;
}
while (r) {
should_add[++should_add[0]] = rot[r];
r -= r & -r;
}
_query(w, 1, M_point, num);
}
}
int lca(int x, int y)
{
if (depth[x] < depth[y]) x ^= y ^= x ^= y;
if (depth[x] != depth[y]) {
int delta = depth[x] - depth[y];
DNF(i, 17, 0) if (delta >> i & 1) x = anc[x][i];
}
if (x == y) return x;
DNF(i, 17, 0) if (anc[x][i] && anc[y][i] && anc[x][i] != anc[y][i]) {
x = anc[x][i]; y = anc[y][i];
}
return anc[x][0];
}
void work(int now)
{
if (ev[now].type == appear) {
segment_tree::insert(ev[now].l, ev[now].r, ev[now].w);
}
else if (ev[now].type == disappear) {
segment_tree::remove(ev[now].l, ev[now].r, ev[now].w);
}
else {
segment_tree::query(1, ev[now].l, ev[now].w, ev[now].num);
}
}
bool cmp(const Event &a, const Event &b)
{
return a.time < b.time || a.time == b.time && a.type < b.type;
}
bool cmp2(const Event &a, const Event &b)
{
return a.w < b.w;
}
void add(int x, int y)
{
nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;
}
void dfs(int now, int pa)
{
depth[now] = depth[pa] + 1;
anc[now][0] = pa;
for (int i = 1; anc[now][i - 1]; i++)
anc[now][i] = anc[anc[now][i - 1]][i - 1];
dfn[now] = ++INDEX;
for (int i = head[now]; i != -1; i = nxt[i]) {
if (data[i] != pa) dfs(data[i], now);
}
ed[now] = INDEX;
}
int find_fa(int now, int depth)
{
FOR(i, 0, 17) if (depth >> i & 1) now = anc[now][i];
return now;
}
int main()
{
freopen("fruit.in", "r", stdin);
freopen("fruit.out", "w", stdout);
memset(head, -1, sizeof head);
in(n); in(p); in(q);
FOR(i, 1, n - 1) {
int u, v; in(u); in(v); add(u, v);
}
dfs(1, 0);
FOR(i, 1, p) {
int u, v, w;
in(u); in(v); in(w);
int anc = lca(u, v);
if (dfn[u] > dfn[v]) u ^= v ^= u ^= v;
if (u == anc) {
int nodes = find_fa(v, depth[v] - depth[u] - 1);
int ss = dfn[nodes], tt = ed[nodes];
if (ss != 1) {
ev[++ev_tot].time = 1;
ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v];
ev[ev_tot].type = appear; ev[ev_tot].w = w;
ev[++ev_tot].time = ss - 1;
ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v];
ev[ev_tot].type = disappear; ev[ev_tot].w = w;
}
if (tt != n) {
ev[++ev_tot].time = dfn[v];
ev[ev_tot].l = tt + 1; ev[ev_tot].r = n;
ev[ev_tot].type = appear; ev[ev_tot].w = w;
ev[++ev_tot].time = ed[v];
ev[ev_tot].l = tt + 1; ev[ev_tot].r = n;
ev[ev_tot].type = disappear; ev[ev_tot].w = w;
}
}
else {
ev[++ev_tot].time = dfn[u]; ev[ev_tot].l = dfn[v];
ev[ev_tot].r = ed[v]; ev[ev_tot].type = appear; ev[ev_tot].w = w;
ev[++ev_tot].time = ed[u]; ev[ev_tot].l = dfn[v];
ev[ev_tot].r = ed[v]; ev[ev_tot].type = disappear; ev[ev_tot].w = w;
}
}
std::sort(ev + 1, ev + ev_tot + 1, cmp2);
FOR(i, 1, ev_tot) {
if (i != 1 && ev[i].w == ev[i - 1].w) continue;
M[ev[i].w] = ++M_point;
to[M_point] = ev[i].w;
}
FOR(i, 1, ev_tot) {
ev[i].w = M[ev[i].w];
}
FOR(i, 1, q) {
int u, v, w;
in(u); in(v); in(w);
if (dfn[u] > dfn[v]) u ^= v ^= u ^= v;
ev[++ev_tot].time = dfn[u];
ev[ev_tot].l = dfn[v]; ev[ev_tot].w = w;
ev[ev_tot].num = i; ev[ev_tot].type = query;
}
std::sort(ev + 1, ev + ev_tot + 1, cmp);
segment_tree::initialize();
FOR(i, 1, ev_tot) work(i);
FOR(i, 1, q) printf("%d\n", to[ans[i]]);
return 0;
}
按照逆序拓扑排序,然后构造字典序最大的解。
#include
using std::priority_queue;
typedef long long LL;
#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)
template <typename Tp> void in(Tp &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
const int MAXN = 100010;
int T, n, m, chose, du[MAXN], order[MAXN];
int cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1];
priority_queue<int>q;
void add(int x, int y)
{
nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;
}
int main()
{
freopen("dishes.in", "r", stdin);
freopen("dishes.out", "w", stdout);
in(T);
while (T--) {
memset(du, 0, sizeof du);
memset(head, -1, sizeof head); cnt = 0;
in(n); in(m); chose = n;
FOR(i, 1, m) {
int x, y; in(x); in(y); add(y, x);
du[x]++;
}
FOR(i, 1, n) {
if (!du[i]) q.push(i);
}
order[0] = 0;
while (!q.empty()) {
int now = q.top(); q.pop(); chose--;
order[++order[0]] = now;
for (int i = head[now]; i != -1; i = nxt[i]) {
du[data[i]]--;
if (!du[data[i]]) {
q.push(data[i]);
}
}
}
if (chose) puts("Impossible!");
else {
DNF(i, n, 1) printf("%d ", order[i]);
putchar(10);
}
}
return 0;
}
考虑没有环的情况。
每个点(除了 1 号点)任选一条入边,则构成一棵脉络树。
所有方案数为 ∏ni=2degree[i]
但是有环,所以答案要减去它。
设 S 为 y 到 x 的路径。
remove=∑S∏ni=2[i∉S]degree[i]
这个可以dp……
令 f[i] 为 i 到 x 的路径求出的remove。
则 f[i]=∑j−>if[j]/degree[i]
#include
using std::queue;
typedef long long LL;
#define FOR(i, a, b) for (LL i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (LL i = (a), i##_END_ = (b); i >= i##_END_; i--)
template <typename Tp> void in(Tp &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
const LL MOD = 1000000007;
const LL MAXN = 200010;
LL n, m, x, y, ans = 1;
LL f[MAXN], du[MAXN], rdu[MAXN];
LL head[MAXN], data[MAXN], nxt[MAXN], cnt;
LL head1[MAXN], data1[MAXN], nxt1[MAXN], cnt1;
queue q;
void add(LL x, LL y)
{
nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
}
void add2(LL x, LL y)
{
nxt1[cnt1] = head1[x]; data1[cnt1] = y; head1[x] = cnt1++;
}
LL power(LL x, LL y)
{
LL ret = 1;
while (y) {
if (y & 1) ret = 1ll * ret * x % MOD;
x = 1ll * x * x % MOD;
y >>= 1;
}
return ret;
}
int main()
{
freopen("maple.in", "r", stdin);
freopen("maple.out", "w", stdout);
memset(head, -1, sizeof head);
memset(head1, -1, sizeof head1);
in(n); in(m); in(x); in(y);
FOR(i, 1, m) {
LL u, v;
in(u); in(v); add(u, v); add2(v, u);
du[v]++; rdu[v]++;
}
FOR(i, 2, n)
if (i != y)
ans = 1ll * ans * du[i] % MOD;
if (x == y || y == 1) {
if (y != 1)
ans = 1ll * ans * du[x] % MOD;
printf("%lld\n", ans);
return 0;
}
LL tmp = ans;
ans = 1ll * ans * (du[y] + 1) % MOD;
FOR(i, 1, n) {
if (!du[i]) q.push(i);
}
while (!q.empty()) {
LL now = q.front(); q.pop();
if (now == y) {
f[now] = tmp;
}
else {
f[now] = 0;
for (LL i = head1[now]; i != -1; i = nxt1[i]) {
f[now] = (f[now] + f[data1[i]]) % MOD;
}
f[now] = 1ll * f[now] * power(rdu[now], MOD - 2) % MOD;
}
for (LL i = head[now]; i != -1; i = nxt[i]) {
du[data[i]]--;
if (!du[data[i]]) {
q.push(data[i]);
}
}
}
printf("%lld\n", (ans - f[x] + MOD) % MOD);
return 0;
}
这是一道动态点分治的题目。但因为我还没有搞这个专题所以暂且跳过。
这个题目还是很容易的。
因为所有的 x 互不相同, 所以可以把大小关系看作是图论中的边。
那么构成的就是一座森林(把相等的点用并差集缩起来)。
然后就可以树形dp辣!
因为有等于,所以我们不知道每棵子树中有多少“块”元素。
我们把相等的元素看成一块,那么一棵子树就是若干个块的大小关系。
我们设第 i 个点的子树中有 j 个块的方案数为 f[i][j] 。
则两棵子树合并的结果 g[i] 为
#include
typedef long long LL;
#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)
#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)
template <typename Tp> void in(Tp &x) {
char ch = getchar(); x = 0;
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}
template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}
template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}
template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}
const int MAXN = 110;
const int MOD = 1000000007;
struct Edge {
int l, r;
} edge[MAXN];
int edge_lenth;
int n, m;
char compare[10];
int du[MAXN], f[MAXN][MAXN];
int head[MAXN], nxt[MAXN], data[MAXN], cnt;
int fa[MAXN];
int find(int x)
{
int tmp = x, pre;
while (tmp != fa[tmp]) tmp = fa[tmp];
while (x != tmp) {
pre = fa[x]; fa[x] = tmp; x = pre;
}
return tmp;
}
void merge(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx != fy) fa[fx] = fy;
}
int g[MAXN], jie[MAXN], ni[MAXN];
int C(int x, int y)
{
if (!y) return 1;
if (x < y) return 0;
return 1ll * jie[x] * ni[y] % MOD * ni[x - y] % MOD;
}
void dfs(int now)
{
for (int i = head[now]; i != -1; i = nxt[i]) dfs(data[i]);
memset(g, 0, sizeof g);
if (head[now] != -1)
FOR(k, 1, n) g[k] = f[data[head[now]]][k];
if (head[now] != -1)
for (int i = nxt[head[now]]; i != -1; i = nxt[i]) {
memset(f[now], 0, sizeof f[now]);
FOR(k, 1, n) FOR(l, 1, n) FOR(j, Max(k, l), Min(n, k + l)) {
f[now][j] = (
f[now][j] +
1ll * g[k] % MOD * f[data[i]][l] % MOD *
C(j, k) % MOD * C(k, k + l - j) % MOD
) % MOD;
}
FOR(k, 1, n) g[k] = f[now][k];
}
if (head[now] == -1) f[now][1] = 1;
else FOR(i, 1, n) f[now][i] = g[i - 1];
}
int power(int x, int y)
{
int ret = 1;
while (y) {
if (y & 1) ret = 1ll * ret * x % MOD;
x = 1ll * x * x % MOD;
y >>= 1;
}
return ret;
}
void add(int x, int y)
{
nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;
}
int main()
{
freopen("pairwise.in", "r", stdin);
freopen("pairwise.out", "w", stdout);
memset(head, -1, sizeof head);
jie[0] = 1;
FOR(i, 1, 100) jie[i] = 1ll * jie[i - 1] * i % MOD;
ni[100] = power(jie[100], MOD - 2);
DNF(i, 99, 1) ni[i] = 1ll * ni[i + 1] * (i + 1) % MOD;
ni[0] = 1;
in(n); in(m);
FOR(i, 1, n) fa[i] = i;
FOR(i, 1, m) {
int x, y;
in(x); scanf("%s", compare); in(y);
if (compare[0] == '<') {
edge[++edge_lenth].l = x; edge[edge_lenth].r = y;
}
else merge(x, y);
}
int ans = 0;
FOR(i, 1, edge_lenth) {
int fx = find(edge[i].l);
int fy = find(edge[i].r);
if (fx == fy) {
puts("0");
return 0;
}
add(fx, fy); du[fy]++;
}
int rot = 0;
FOR(i, 1, n) {
if (!du[find(i)]) rot = find(i);
}
if (!rot) {
puts("0");
return 0;
}
dfs(rot);
FOR(i, 1, n) ans = (ans + f[rot][i]) % MOD;
printf("%d\n", ans);
return 0;
}