@2368860385
2018-12-19T13:08:06.000000Z
字数 5069
阅读 184
比赛总结
预计:50+40=90
实际:50+40=90
T1:
50分比较好写,找了写性质,没想到什么更优秀的性质,于是打了一个搜索,一个dp,拍上了。继续想了会儿,没有想出正解。
T2:
看了题目后,没有什么思路,10分的比较好写,想先看T3回来再写。
T3:
看完后,感觉好像就是模拟在树上走一走,求最大值,感觉不像是这么简单,又想了会儿,没想到反例,就开始写了。写完后又写了暴力,没拍上,调了几个bug。最后发现一个bug是反向走的时候要判断是否走到点上,时间有点紧,有点紧张,没有想出怎么判。写了一个二分+倍增判段,还是拍不上。最后把暴力粘上,写上数据分治就交了。
暴力:30
有bug的算法:30
暴力+有bug的算法+数据分治:40(交的这份)
暴力+写错的二分+倍增判断是否走到点上:60(早知道就把写错的二分+倍增粘上了。。。)
数据好像有点水。。。
总结:
最后有点慌,思绪有点混乱,加上这道题本来就分类较多,细节较多,最后没调出。
时间分配
调试过程中:调出一个bug,多了新bug,导致一直拍不上。
打完50分暴力,找了些性质,但是没有想出什么更优秀的方法。
整理后AC代码,题解在代码上方。
/*
1、转化
考虑每一列必定会出现两种颜色,而有一种颜色不会出现。
所以可以补集转化为一个长度为m的序列,每列的颜色是未出现的颜色。
每四个方格都要有三种颜色=>这个序列中没有相邻的同色的。
此时问题就是求多少个这样的序列,相邻位置不同色,恰好出现M-R种red,M-G中green,M-B种blue。
2、
然后枚举第一个颜色是什么,分成三种情况讨论。
设第一种颜色为x,其余两种分别为y,z
此时x中颜色分别在x个不相邻的位置,可能会分成x个段,或者x-1个段,再次分情况讨论,设段数为g。
3、
枚举长度为偶数的段数,设为e,那么这些段中,出现的yz的个数是一样的,(出现一个y必定有一个z)。
奇数段的开头可能是y,也可能是z,设oy是以y开头段数,oz是以z开头的段数
那么有
1、oy+oz=g-e ------ 奇数段和偶数段的和是分成的总段数g
2、y(-e)-oy=z(-e)-oz ------ 同样,奇数段去掉开头后相当于一个偶数段(出现的yz的个数是一样的),那么yz各自去掉奇数段yz开头的颜色后,yz出现的颜色一样的。
可以求出oz,oy。
4、
然后此时剩下的yz颜色(yz颜色表示yz一起出现)为 y-oy-e,设为r
------ 总的y - 奇数段单独出现的y的个数 - 偶数段的开头的个数(偶数段的前两个位置必定一个y,后面也许还有许多yz)= 剩下的y(这些y中的每一个和一个z一起出现在奇数段后者偶数段)
Finally:
将这r段(yz颜色)在g段中选r个放上 --- C(g+r+1,r)
在这g段选e段为偶数段 --- C(g,e)
在这g-e段奇数段选oy段y开头 --- C(g-e,oy)
每个偶数段可以y开头,也可以z开头 --- 2^e
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int mod = 1e9 + 7;
const int N = 1000000;
int fac[N + 5], ifac[N + 5], mi[N + 5];
int ksm(int a,int b) {
int res = 1;
while (b) {
if (b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
void init() {
fac[0] = 1;
for (int i = 1; i <= N; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
ifac[N] = ksm(fac[N], mod - 2);
for (int i = N; i >= 1; --i) ifac[i - 1] = 1ll * ifac[i] * i % mod;
mi[0] = 1;
for (int i = 1; i <= N; ++i) mi[i] = 1ll * mi[i - 1] * 2 % mod;
}
int C(int n,int m) {
return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
int Calc(int n,int x,int y,int z) {
if (x <= 0) return 0;
LL ans = 0;
for (int g = x - 1; g <= x; ++g) {
if (g <= 0) continue;
for (int e = 0; e <= g; ++e) {
if ((g - e + y - z) & 1) continue;
int oy = (g - e + y - z) / 2;
int oz = g - e - oy;
if (oy < 0 || oz < 0) continue;
if (((y + z - e - g) < 0) || ((y + z - e - g) & 1)) continue;
int r = (y + z - e - g) / 2;
ans += 1ll * C(g + r - 1, r) * C(g, e) % mod * C(g - e, oy) % mod * mi[e] % mod;
}
}
return ans % mod;
}
int main() {
init();
int M = read(), R = read(), G = read(), B = read();
LL ans = 0;
R = M - R, G = M - G, B = M - B;
ans += 2 * Calc(M, R, G, B);
ans += 2 * Calc(M, G, B, R);
ans += 2 * Calc(M, B, R, G);
cout << ans % mod;
return 0;
}
本来想写10分的来着,去看T3了。
首先求路径交。
然后分为两种情况:
1、在路径交上同向走,那么要求时间差<路径交的最大的边。
2、反向走,要求经过路径交的时间区间有交集,并且不能走到点上。
整理后AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
#define pa pair<LL,int>
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int N = 100005;
const int Log = 21;
struct Edge{
int to, nxt; LL w;
Edge() {}
Edge(int a,int b, LL c) { to = a, nxt = b, w = c; }
}e[N << 1];
int head[N], f[N][22], deth[N], fa[N], st[N], ed[N], En, Index;
LL sum[N], g[N][22];
int n;
inline void add_edge(int u,int v, LL w) {
++En; e[En] = Edge(v, head[u], w); head[u] = En;
++En; e[En] = Edge(u, head[v], w); head[v] = En;
}
void dfs(int u) {
st[u] = ++Index;
deth[u] = deth[fa[u]] + 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == fa[u]) continue;
f[v][0] = fa[v] = u; g[v][0] = e[i].w; sum[v] = sum[u] + e[i].w;
dfs(v);
}
ed[u] = Index;
}
inline int LCA(int u,int v) {
if (deth[u] < deth[v]) swap(u, v);
int d = deth[u] - deth[v];
for (int j = Log; j >= 0; --j)
if (d & (1 << j)) u = f[u][j];
if (u == v) return u;
for (int j = Log; j >= 0; --j)
if (f[u][j] != f[v][j]) u = f[u][j], v = f[v][j];
return f[u][0];
}
inline LL getRoad(int u,int v) {
int lca = LCA(u, v);
return sum[u] + sum[v] - sum[lca] - sum[lca];
}
inline LL getmx(int u,int v) {
int lca = LCA(u, v); LL ans = 0;
for (int j = Log; j >= 0; --j)
if (deth[f[u][j]] >= deth[lca]) ans = max(ans, g[u][j]), u = f[u][j];
for (int j = Log; j >= 0; --j)
if (deth[f[v][j]] >= deth[lca]) ans = max(ans, g[v][j]), v = f[v][j];
return ans;
}
void Judge(int u,LL len) {
for (int i = Log; i >= 0; --i)
if (getRoad(u, f[u][i]) <= len) len -= getRoad(u, f[u][i]), u = f[u][i];
puts(len == 0 ? "NO" : "YES");
}
void solve() {
int u1 = read(), v1 = read(); LL t1; scanf("%lld", &t1); // 此处需开longlong
int u2 = read(), v2 = read(); LL t2; scanf("%lld", &t2);
int lca = LCA(u2, v2), S, T;
int f1 = LCA(u1, u2), f2 = LCA(u1, v2);
int g1 = LCA(v1, u2), g2 = LCA(v1, v2);
// 求路径交,若没有,则相交于一点lca处
if (st[u1] < st[lca] || st[u1] > ed[lca]) S = lca;
else S = deth[f1] > deth[f2] ? f1 : f2;
if (st[v1] < st[lca] || st[v1] > ed[lca]) T = lca;
else T = deth[g1] > deth[g2] ? g1 : g2;
bool fx = getRoad(u2, S) > getRoad(u2, T); // 方向
t1 += getRoad(u1, S);
t2 += fx ? getRoad(u2, T) : getRoad(u2, S);
if (!fx) {
puts((abs(t1 - t2) < getmx(S, T)) ? "YES" : "NO");
}
else {
LL len = getRoad(S, T);
if (abs(t1 - t2) > len) { puts("NO"); return ; } // 经过路径的时间区间没有交集
len += t1 + t2; // uv从开始知道走完相交的路径所花的时间
if (len & 1) { puts("YES"); return ; }
len /= 2; int Mid = LCA(S, T); // len/2 相遇的时间
if (getRoad(S, Mid) >= len - t1) Judge(S, len - t1);
else Judge(T, len - t2);
}
}
int main() {
n = read();int Q = read();
for (int i = 1; i < n; ++i) {
int u = read(), v = read(); LL w; scanf("%lld", &w);
add_edge(u, v, w);
}
dfs(1);
for (int j = 1; j <= Log; ++j)
for (int i = 1; i <= n; ++i) {
f[i][j] = f[f[i][j - 1]][j - 1];
g[i][j] = max(g[i][j - 1], g[f[i][j - 1]][j - 1]);
}
while (Q--) solve();
return 0;
}