「美团 CodeM 初赛 Round A」试题泛做
最长树链
树形DP。我们发现gcd是多少其实并不重要,只要不是1就好了,此外只要有一个公共的质数就好了。计f[i][j]表示i子树内含有j因子的最长链是多少。因为一个数的不同的质因子个数是log级别的,所以转移的复杂度是log方的。所以总共的时间复杂度就是nlog^2n。
#include <cstdio>
#include <vector>
#include <map> #define R register
#define maxn 100010
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
bool vis[maxn];
int pr[maxn / ], prcnt, v[maxn];
struct Edge {
Edge *next;
int to;
} *last[maxn], e[maxn << ], *ecnt = e;
inline void link(R int a, R int b)
{
*++ecnt = (Edge) {last[a], b}; last[a] = ecnt;
*++ecnt = (Edge) {last[b], a}; last[b] = ecnt;
}
int p[maxn][], pc[maxn];
int f[maxn][];
int ans;
void dfs(R int x, R int fa)
{
for (R Edge *iter = last[x]; iter; iter = iter -> next)
if (iter -> to != fa)
{
dfs(iter -> to, x);
for (R int i = ; i <= pc[x]; ++i)
{
R int nx = p[x][i];
for (R int j = ; j <= pc[iter -> to]; ++j)
if (p[iter -> to][j] == nx)
{
cmax(ans, f[x][i] + f[iter -> to][j] + );
cmax(f[x][i], f[iter -> to][j]);
}
}
}
for (R int i = ; i <= pc[x]; ++i) ++f[x][i];
}
int main()
{
R int n; scanf("%d", &n);
for (R int i = ; i < maxn; ++i)
{
if (!vis[i]) pr[++prcnt] = i;
for (R int j = ; j <= prcnt && i * pr[j] < maxn; ++j)
{
vis[i * pr[j]] = ;
if (i % pr[j] == ) break;
}
}
for (R int i = ; i < n; ++i)
{
R int a, b; scanf("%d%d", &a, &b);
link(a, b);
}
for (R int i = ; i <= n; ++i)
{
scanf("%d", v + i);
R int temp = v[i];
for (R int j = ; 1ll * pr[j] * pr[j] <= v[i] && temp != ; ++j)
if (temp % pr[j] == )
{
p[i][++pc[i]] = pr[j];
while (temp % pr[j] == ) temp /= pr[j];
}
temp != ? p[i][++pc[i]] = temp : ;
}
dfs(, );
printf("%d\n", ans);
return ;
}
最长树链
二分图染色
校内训练zzx出给我们做的。相当于求两个匹配的集合,使得两个集合的交集为空集。先设f[i]表示左边i个顶点,右边i个顶点的匹配的方案数。这个可以递推来求。然后再容斥一下,枚举交集为S的方案数。然后我们发现之和S的大小有关,所以就可以只枚举集合大小,剩下的用组合数算一算。
#include <cstdio> #define R register
#define maxn 10000010
const int mod = 1e9 + ;
int f[maxn], pw[maxn], inp[maxn];
inline int qpow(R int base, R int power)
{
R int ret = ;
for (; power; power >>= , base = 1ll * base * base % mod)
power & ? ret = 1ll * ret * base % mod : ;
return ret;
}
inline int C(R int n, R int m)
{
return 1ll * pw[n] * inp[n - m] % mod;
}
int main()
{
R int n; scanf("%d", &n);
f[] = ; f[] = ;
for (R int i = ; i <= n; ++i)
f[i] = (2ll * f[i - ] - 1ll * (i - ) * (i - ) % mod * f[i - ] + 2ll * (i - ) * f[i - ]) % mod;
pw[] = ;
for (R int i = ; i <= n; ++i) pw[i] = 1ll * pw[i - ] * i % mod;
inp[n] = qpow(pw[n], mod - );
for (R int i = n; i; --i) inp[i - ] = 1ll * inp[i] * i % mod;
R int ans = ;
for (R int i = , p = ; i <= n; ++i, p = -p)
(ans += (mod + 1ll * p * inp[i] * C(n, i) % mod * C(n, i) % mod * f[n - i] % mod * f[n - i] % mod) % mod) %= mod;
printf("%d\n", ans);
return ;
}
二分图染色
倒水
我一开始想了半天的二分,然后后来发现只要大力分类讨论三种情况就好了。。。T小于温度最小值的,T大于温度最大值的,T在中间的。
最后一种是不成立的(因为最终的温度不可能大于或小于T,又因为T不可能和不等于T的水混合成T,所以不成立)。第一种只要看能否混成最小值就好了,第三种看一下能否混成最大值,如果能的话就把所有的水都用掉。
#include <cstdio> #define R register
#define maxn 100010
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
typedef double db;
int n, T, C, t[maxn], c[maxn];
db left;
inline bool check(R db x)
{
left = C;
for (R int i = ; i <= n; ++i)
if (t[i] != x)
{
if (T == x) return ;
left -= (x * c[i] - (db) t[i] * c[i]) / (T - x);
}
return left >= ;
}
int main()
{
scanf("%d%d%d", &n, &T, &C);
R int maxx = , minn = 0x7fffffff;
for (R int i = ; i <= n; ++i) scanf("%d%d", t + i, c + i), cmax(maxx, t[i]), cmin(minn, t[i]);
if (T <= minn)
{
if (check(minn)) printf("Possible\n%.4lf\n", (db) minn);
else puts("Impossible");
}
else if (T >= maxx)
{
if (!check(maxx)) puts("Impossible");
else
{
R db p1 = (db) T * C, p2 = C;
for (R int i = ; i <= n; ++i) p1 += (db) t[i] * c[i], p2 += c[i];
printf("Possible\n%.4lf\n", p1 / p2);
}
}
else puts("Impossible");
return ;
}
倒水
身体训练
一开始题目看错傻逼了半天QAQ。。。设f[i][j]为第i个人排在第j位所需要的时间,我们发现这种情况出现的概率恰好是n!/(n-1)!=1/n次。所以直接乘上去加起来就好了。
#include <cstdio> #define R register
#define maxn 1010
typedef double db;
db c[maxn], d[maxn];
int main()
{
R int n; R db v, u; scanf("%d%lf%lf", &n, &v, &u);
for (R int i = ; i <= n; ++i) scanf("%lf", c + i);
for (R int i = ; i <= n; ++i) scanf("%lf", d + i);
R db ans = ;
for (R int i = ; i <= n; ++i)
{
for (R int j = ; j < n; ++j)
ans += u / (c[i] - d[i] * j - v);
}
printf("%.3lf\n", ans);
return ;
}
身体训练
合并回文子串
又是zzx校内训练出给我们做的。我们发现最终序列的一个子串在原本的两个序列上对应的是两个区间。所以我们计f[l1][r1][l2][r2]为用A[l1..r1],B[l2..r2]的字符能否组成一个回文串。然后转移的时候只要在端点转移进来。然后这个DP可以用bitset优化,然而我没去写。。。
#include <cstdio>
#include <cstring> #define R register
#define maxn 60
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
bool f[maxn][maxn][maxn][maxn];
char A[maxn], B[maxn];
int main()
{
R int T; scanf("%d", &T);
for (; T; --T)
{
scanf("%s%s", A + , B + );
R int n = strlen(A + ), m = strlen(B + );
memset(f, , sizeof (f));
for (R int i = ; i <= n + ; ++i)
for (R int j = ; j <= m + ; ++j)
f[i][i - ][j][j - ] = f[i][i][j][j - ] = f[i][i - ][j][j] = ;
for (R int ln = ; ln <= n; ++ln)
for (R int l1 = , r1 = ln; r1 <= n; ++l1, ++r1)
for (R int lm = ; lm <= m; ++lm)
for (R int l2 = , r2 = lm; r2 <= m; ++l2, ++r2)
{
f[l1][r1][l2][r2] |= f[l1 + ][r1][l2][r2 - ] && A[l1] == B[r2];
f[l1][r1][l2][r2] |= f[l1][r1 - ][l2 + ][r2] && A[r1] == B[l2];
if (ln > ) f[l1][r1][l2][r2] |= A[l1] == A[r1] && f[l1 + ][r1 - ][l2][r2];
if (lm > ) f[l1][r1][l2][r2] |= B[l2] == B[r2] && f[l1][r1][l2 + ][r2 - ];
}
R int ans = ;
for (R int i = ; i <= n; ++i)
for (R int j = i; j <= n; ++j)
for (R int ii = ; ii <= m; ++ii)
for (R int jj = ii; jj <= m; ++jj)
f[i][j][ii][jj] ? cmax(ans, j - i + + jj - ii + ) : ;
printf("%d\n", ans);
}
return ;
}
合并回文子串
数列互质
我会分块莫队(°∀°)ノ!我们注意到一个性质:出现次数超过sqrt(n)的数不会超过sqrt(n)个。我们把这些数成为关键的数,并且可以预处理出它出现次数的前缀和。对于剩下的数出现次数就不会超过sqrt(n)了。我们用莫队把区间内所有非关键数的出现次数处理出来,并且可以处理出 出现次数为i的数的出现次数(好绕口)。。。对于每一个询问的k,先枚举关键的数,看一下出现次数是否满足条件。再枚举一下非关键数里面满足条件的数的个数。时间复杂度q*sqrt(n)*log,那个log是求gcd的。。。一开始直接求gcd被卡T了。后来预处理一下不知怎地就过了。╮( ̄▽ ̄)╭
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring> #define R register
#define maxn 50010
#define maxs 233
int sum[maxs][maxn], cnt[maxn], a[maxn], ans[maxn], idd[maxn], ccnt[maxs], ip[maxs], gg[][];
struct Query {
int l, r, k, id;
inline bool operator < (const Query &that) const {return idd[l] < idd[that.l] || (idd[l] == idd[that.l] && (idd[l] & ? r > that.r : r < that.r));}
} q[maxn];
bool imp[maxn];
int gcd(R int a, R int b)
{
return !b ? a : gcd(b, a % b);
}
int ggcd(R int a, R int b)
{
if (!a || !b) return a + b;
if (a <= && b <= ) return gg[a][b];
return ggcd(b, a % b);
}
inline void add(R int x)
{
if (imp[x]) return ;
cnt[x] ? --ccnt[cnt[x]] : ;
++ccnt[++cnt[x]];
}
inline void del(R int x)
{
if (imp[x]) return ;
--ccnt[cnt[x]--];
cnt[x] ? ++ccnt[cnt[x]] : ;
}
int main()
{
R int n, m, num = , sq; scanf("%d%d", &n, &m); sq = (int) sqrt(n); sq < ? sq = : ;
for (R int i = ; i <= n; ++i) scanf("%d", a + i), ++cnt[a[i]], idd[i] = i / sq;
for (R int i = ; i <= n; ++i)
{
if (cnt[i] >= sq)
{
ip[++num] = i; imp[i] = ;
// printf("i %d\n", i);
for (R int j = ; j <= n; ++j)
sum[num][j] = sum[num][j - ] + (a[j] == i);
}
}
memset(cnt, , sizeof (cnt));
for (R int i = ; i <= m; ++i) scanf("%d%d%d", &q[i].l, &q[i].r, &q[i].k), q[i].id = i;
for (R int i = ; i <= ; ++i)
for (R int j = ; j <= ; ++j)
gg[i][j] = gcd(i, j);
std::sort(q + , q + m + );
R int l = , r = ;
for (R int i = ; i <= m; ++i)
{
while (q[i].r > r) add(a[++r]);
while (q[i].l < l) add(a[--l]);
while (q[i].l > l) del(a[l++]);
while (q[i].r < r) del(a[r--]);
for (R int j = ; j <= sq; ++j)
if (ggcd(j, q[i].k) == ) ans[q[i].id] += ccnt[j];
for (R int j = ; j <= num; ++j)
if (sum[j][q[i].r] - sum[j][q[i].l - ] > && ggcd(sum[j][q[i].r] - sum[j][q[i].l - ], q[i].k) == ) ++ans[q[i].id];
}
for (R int i = ; i <= m; ++i) printf("%d\n", ans[i]);
return ;
}
数列互质
「美团 CodeM 初赛 Round A」试题泛做的更多相关文章
- #6164. 「美团 CodeM 初赛 Round A」数列互质-莫队
#6164. 「美团 CodeM 初赛 Round A」数列互质 思路 : 对这个题来言,莫队可以 n*根号n 离线处理出各个数出现个的次数 ,同时可以得到每个次数出现的次数 , 但是还要处理有多少 ...
- loj #6177. 「美团 CodeM 初赛 Round B」送外卖2 状压dp floyd
LINK:#6177.美团 送外卖2 一道比较传统的状压dp题目. 完成任务 需要知道自己在哪 已经完成的任务集合 自己已经接到的任务集合. 考虑这个dp记录什么 由于存在时间的限制 考虑记录最短时间 ...
- 【loj6177】「美团 CodeM 初赛 Round B」送外卖2 Floyd+状压dp
题目描述 一张$n$个点$m$条边的有向图,通过每条边需要消耗时间,初始为$0$时刻,可以在某个点停留.有$q$个任务,每个任务要求在$l_i$或以后时刻到$s_i$接受任务,并在$r_i$或以前时刻 ...
- 「美团 CodeM 初赛 Round A」最长树链
题目描述 Mr. Walker 最近在研究树,尤其是最长树链问题.现在树中的每个点都有一个值,他想在树中找出最长的链,使得这条链上对应点的值的最大公约数不等于1.请求出这条最长的树链的长度. 输入格式 ...
- Loj #6164. 「美团 CodeM 初赛 Round A」数列互质
link : https://loj.ac/problem/6164 莫队傻题,直接容斥做. #include<bits/stdc++.h> #define maxn 100005 #de ...
- 【填坑】loj6159. 「美团 CodeM 初赛 Round A」最长树链
水一水 枚举各个质数,把是这个数倍数的点留下,跑直径,没了 #include <bits/stdc++.h> using namespace std; int h,t,n,p,q,M,N; ...
- LiberOJ#6178. 「美团 CodeM 初赛 Round B」景区路线规划 概率DP
题意 游乐园被描述成一张 n 个点,m 条边的无向图(无重边,无自环).每个点代表一个娱乐项目,第 i 个娱乐项目需要耗费 ci 分钟的时间,会让小 y 和妹子的开心度分别增加 h1i ,h2i ,他 ...
- loj6177 「美团 CodeM 初赛 Round B」送外卖2 最短路+状压dp
题目传送门 https://loj.ac/problem/6177 题解 一直不知道允不允许这样的情况:取了第一的任务的货物后前往配送的时候,顺路取了第二个货物. 然后发现如果不可以这样的话,那么原题 ...
- 「美团 CodeM 资格赛」试题泛做
LibreOJ真是吼啊! 数码 推个式子,把枚举因数转为枚举倍数.然后就发现它是根号分段的.然后每一段算一下就好了. #include <cstdio> #include <cstr ...
随机推荐
- Neo4j Cypher语法(三)
目录 5 函数 5.1 谓词函数 5.2 标量函数 5.3 聚合函数 5.4 列表函数 5.5 数学函数 5.6 字符串函数 5.7 Udf与用户自定义函数 6 模式 6.1 索引 6.2 限制 7 ...
- date和time
time和date两个函数在Lua中实现所有的时钟查询功能.函数time在没有参数时返回当前时钟的数值. t=os.date()print(t) 05/07/19 16:49:18 --------- ...
- HBASE学习笔记(五)
一.HBase的RowKey设计原则 1.我们知道HBase是三维有序存储的,通过RowKey(行键),ColumnKey(Column family和qualifier)和TimeStamp(时间戳 ...
- a标签 href不跳转 禁止跳转
当页面中a标签不需要任何跳转时,从原理上来讲,可分如下两种方法: 标签属性href,使其指向空或不返回任何内容.如: <a href="javascript:void(0);" ...
- 1 .net将xml反序列化
public static T XmlToObject<T>(string str) where T : class { using (Stream stream = new Memory ...
- Java经典基础与高级面试36题和答案
1.”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法? “static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实 ...
- Nginx作为静态资源web服务之跨域访问
Nginx作为静态资源web服务之跨域访问 首先了解一下什么是跨域 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器施加的安全限制. 所谓同源是指,域名,协议,端口均相 ...
- vue-cli3.x创建项目vue create hello-world
在git中输入指令vue create hello-world,没反应,因为vue-cli的版本问题,必须3.x版本才能使用这个指令于是按照官网的提示升级vue vue-cli从2.x版本升级到3.x ...
- JAVA语言程序设计课后习题----第一单元解析(仅供参考)
1 本题是水题,基本的输出语句 public class test { public static void main(String[] args) { // 相邻的两个 "" 要 ...
- 【4】Zookeeper数据模型
一.Znode节点是什么 1.1.概念 Znode节点是Zookeeper中数据模型中最小的数据单元.Zookeeper的数据模型是一颗树,由"/"进行分割路径.每个znode ...