codeforces1111 简单题【DE】简要题解
D
很显然可以用一个背包算出来凑齐i个位置的方案
然后总的答案就是\(dp_{n / 2}\)
然后需要扣掉不符合条件的就是把选出来的数的贡献剪掉的贡献
然后注意因为是多重集合的排列,所以需要乘上\(\frac{fac[n / 2]}{fac[cnt_a]fac[cnt_b].....}\ast \frac{fac[n / 2]}{fac[cnt_c]fac[cnt_d].....}\)
然后显然下面是所有个数的阶乘积,然后没了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = 60;
const int Mod = 1e9 + 7;
int add(int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
}
int sub(int a, int b) {
return (a -= b) < 0 ? a + Mod : a;
}
int mul(int a, int b) {
return 1ll * a * b % Mod;
}
int fast_pow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = mul(a, a))
if (b & 1) res = mul(res, a);
return res;
}
int inv[N], fac[N];
int ans[M][M] = {0}, cnt[M];
int n, q, f[N];
char s[N];
int id(char c) {
if ('a' <= c && c <= 'z') {
return c - 'a' + 27;
} else {
return c - 'A' + 1;
}
}
int C(int a, int b) {
return a >= b ? mul(fac[a], mul(inv[b], inv[a - b])) : 0;
}
void modify(int id, int typ) {
if (typ) {
for (int i = n / 2; i >= cnt[id]; i--)
f[i] = add(f[i], f[i - cnt[id]]);
} else {
for (int i = cnt[id]; i <= n / 2; i++)
f[i] = sub(f[i], f[i - cnt[id]]);
}
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
scanf("%s", s + 1);
n = strlen(s + 1);
inv[0] = fac[0] = 1;
for (int i = 1; i <= n; i++)
fac[i] = mul(fac[i - 1], i);
inv[n] = fast_pow(fac[n], Mod - 2);
for (int i = n - 1; i >= 1; i--)
inv[i] = mul(inv[i + 1], i + 1);
for (int i = 1; i <= n; i++)
cnt[id(s[i])]++;
f[0] = 1;
for (int i = 1; i <= 52; i++)
if (cnt[i]) modify(i, 1);
for (int i = 1; i <= 52; i++) if (cnt[i] && cnt[i] <= n / 2) {
modify(i, 0);
ans[i][i] = f[n / 2 - cnt[i]];
modify(i, 1);
}
for (int i = 1; i <= 52; i++) if (cnt[i]) {
modify(i, 0);
for (int j = 1; j <= 52; j++) if (i != j && cnt[j] && cnt[j] + cnt[i] <= n / 2) {
modify(j, 0);
ans[i][j] = f[n / 2 - cnt[i] - cnt[j]];
modify(j, 1);
}
modify(i, 1);
}
int bas = mul(fac[n / 2], fac[n / 2]);
for (int i = 1; i <= 52; i++)
bas = mul(bas, inv[cnt[i]]);
for (int i = 1; i <= 52; i++)
for (int j = 1; j <= 52; j++)
ans[i][j] = mul(ans[i][j], mul(2, bas));
scanf("%d", &q);
while (q--) {
int x, y;
scanf("%d %d", &x, &y);
printf("%d\n", ans[id(s[x])][id(s[y])]);
}
return 0;
}
E
首先如果在虚树上考虑,我们按照深度进行dp
发现\(f_{i,j}\)表示i个点分成j个集合的方案数有转移:
\(f_{i,j}=f_{i - 1,j}\ast (j - h_i)+f_{i - 1,j - 1}\)
其中h是一个节点的父亲个数
然后h咋算呢?
就是可以用i到1的节点个数加上r到1的节点个数减去lca到1的节点个数的两倍
然后以1为根的时候每一个点在dfs序上的贡献都是一个区间,用bit算一下就可以了
然后就直接dp就可以了
因为有多次询问,所以注意边界就可以了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = 5e2 + 10;
const int LOG = 20;
const int Mod = 1e9 + 7;
int add(int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
}
int mul(int a, int b) {
return 1ll * a * b % Mod;
}
int n, q, f[N][M];
vector<int> g[N];
int dep[N], fa[N][LOG];
int bg[N], ed[N], ind = 0;
void dfs(int u, int father) {
dep[u] = dep[father] + 1;
bg[u] = ++ind;
fa[u][0] = father;
for (int i = 1; i < 18; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (auto v : g[u])
if (v != father)
dfs(v, u);
ed[u] = ind;
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
int delta = dep[x] - dep[y];
for (int i = 0; i < 18; i++)
if ((delta >> i) & 1)
x = fa[x][i];
if (x == y) return x;
for (int k = 17; k >= 0; k--) {
if (fa[x][k] != fa[y][k]) {
x = fa[x][k];
y = fa[y][k];
}
}
return fa[x][0];
}
int bit[N];
void modify(int t, int vl) {
for (; t <= n; t += t & (-t))
bit[t] += vl;
}
int query(int t) {
int res = 0;
for (; t; t -= t & (-t))
res += bit[t];
return res;
}
void solve() {
static int h[N], p[N], k, m, r;
static bool mark[N];
scanf("%d %d %d", &k, &m, &r);
for (int i = 1; i <= k; i++)
scanf("%d", &p[i]);
for (int i = 1; i <= k; i++) {
modify(bg[p[i]], 1);
modify(ed[p[i]] + 1, -1);
mark[p[i]] = 1;
}
int hrt = query(bg[r]);
for (int i = 1; i <= k; i++) {
int g = lca(p[i], r);
h[i] = query(bg[p[i]]) + hrt - 2 * query(bg[g]) + mark[g] - 1;
}
for (int i = 1; i <= k; i++) {
modify(bg[p[i]], -1);
modify(ed[p[i]] + 1, 1);
mark[p[i]] = 0;
}
sort(h + 1, h + k + 1); // 相当于在虚树上按照深度进行dp
f[0][0] = 1;
for (int i = 1; i <= k; i++) {
for (int j = 1; j < h[i]; j++)
f[i][j] = 0;
for (int j = h[i]; j <= min(i, m); j++)
f[i][j] = add(mul(j - h[i], f[i - 1][j]), f[i - 1][j - 1]);
}
int res = 0;
for (int i = 1; i <= m; i++)
res = add(res, f[k][i]);
printf("%d\n", res);
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
scanf("%d %d", &n, &q);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
while (q--)
solve();
return 0;
}
codeforces1111 简单题【DE】简要题解的更多相关文章
- 虚树总结&题单&简要题解
简介 虚树,即剔除所有无关结点,只保留询问点和询问点的相关结点(两两之间的LCA),建一棵新树,这棵新树就是虚树.通过虚树,可以有效的减小询问(甚至修改)的复杂度.设询问点的个数是\(k\),那么建虚 ...
- $FFT/NTT/FWT$题单&简要题解
打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...
- 动态淀粉质(划掉)题单&简要题解
简介 动态点分治的思想:还不太清楚诶怎么办. 大概是通过降低树高来降低每次修改和询问的复杂度吧,还可以把树上一个连通块的信息统计到一个点(重心)上.具体实现方式和普通的静态点分治没有太大的区别,只是把 ...
- Codeforces 863 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...
- HDU100题简要题解(2060~2069)
这十题感觉是100题内相对较为麻烦的,有点搞我心态... HDU2060 Snooker 题目链接 Problem Description background: Philip likes to pl ...
- 洛谷 P5057 [CQOI2006]简单题 题解
P5057 [CQOI2006]简单题 题目描述 有一个 n 个元素的数组,每个元素初始均为 0.有 m 条指令,要么让其中一段连续序列数字反转--0 变 1,1 变 0(操作 1),要么询问某个元素 ...
- hectf2020部分简单题题解wp
HECTF 我真是又菜又没时间肝题..又又又只水了波简单题... Reverse 1.Hello_Re file查一波 32bit,拖进IDA中 老规矩shift+F12 查看字符串: 跳转 F5查看 ...
- unctf2020 部分简单题题解
unctf2020 水一波简单题..菜狗前来报道..大佬轻喷..如果有时间做题就好了呜呜呜 misc 1.baba_is_you 题目告诉我们,了解png文件格式. 下载得到一张png格式的图片. 用 ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
随机推荐
- js实现滑动拼图验证码
js实现滑动拼图验证码,我这个样式是仿那些大网站做了, 学习用的,只用到前端. 小的个人网站感觉还可以用,大一点的别人用机器一下就破解了. 下面看图示: 样子大概是这样的. 源码在这 百度网盘: ...
- ListView事件的研究
1. ListView的OnItemClickListener不被触发的另外一种情况 如上图,在一个ItemView中,只有一个TextView位于最左侧,他的右侧是空白区域,没有任何控件,当点击右侧 ...
- HDU 2569 彼岸
彼岸 思路:动态规划.因为不能有连续三个不同的颜色,所以只要看最后三个就可以了. 设dp[n]为长度为n到达彼岸的方案数. ①当第n-2个颜色和第n-1个颜色相同时,第n个位置可以取任意一种颜色,dp ...
- [.NET开发] C#使用doggleReport生成pdf报表的方法
本文实例讲述了C#使用doggleReport生成pdf报表的方法.分享给大家供大家参考,具体如下: 1. 安装nuget -install package DoddleReport -install ...
- android--------自定义视频控件(视频全屏竖屏自动切换)
android播放视频也是常用的技术,今天分享一个自定义视频控件,支持自定义控制 UI,全屏播放, 可以实现自动横竖屏切换的控件,跟随手机的位置而,重力感应自动切换横竖屏. 效果图: 代码下载Gi ...
- JSP页面出现乱码
Jsp文件中会出现下面所示的编码指定方式: <%@ page language="java" contentType="text/html; charset=UTF ...
- python-day10--字符编码
1.回顾: 软件→操作系统→硬件 2.文本编辑器: 启动:硬盘→内存→运行(cpu) 读文件:硬盘→内存→CPU读 存文件:保存到硬盘中 3.python解释器 启动:硬盘→内存→运行(cpu) 读文 ...
- unity3d 博客
博客: 1.http://my.csdn.net/caoboya 2.http://my.csdn.net/OnafioO
- Leetcode 106
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...
- HDU 1934 特殊数字
有两种车牌号.让你判断第二种是不是在第一种之后且在第一种出Kth之前的车牌号. 本解中是把前面的字母看成一位十进制的数.自己是一个26或者21进制的数.如果比较时有两种.那么第一种和第一种的最后一个比 ...