T1:
惨。。当场没读懂题意?
最小割就是选出权值和最小的边集,使得删去它们后图不联通
题目硬性规定要从一棵树内选出有且仅有一条边
假如说题中的图仅仅是一棵树,那么随意割掉一条边就好
现在以这棵树的视角来看
割去一条边后,处理掉联通边两端的联通块的返祖边显然最优(不然你割这条树边干嘛?)
嗯,,至于返祖边的数量,树上前缀和搞定
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2E4 + 20;
int n,m,T,root,fa[maxn][15],L[maxn],pass[maxn],son[maxn];
vector v[maxn];
queue Q;
void dfs(int x,int from)
{
pass[x] = 0;
for (int i = 1; i < 15; i++)
fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if (to == from) continue;
fa[to][0] = x;
L[to] = L[x] + 1;
dfs(to,x);
++son[x];
}
if (!son[x]) Q.push(x);
}
int getint()
{
int ret = 0;
char ch = getchar();
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
int Log; for (Log = 0; L[p] - (1<= 1; Log++); --Log;
for (int j = Log; j >= 0; j--)
if (L[p] - (1<= L[q])
p = fa[p][0];
if (p == q) return p;
for (int j = Log; j >= 0; j--)
if (fa[p][j] != fa[q][j])
p = fa[p][j],q = fa[q][j];
return fa[p][0];
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("cut.in","r",stdin);
freopen("cut.out","w",stdout);
#endif
cin >> T;
while (T--) {
scanf("%d%d",&n,&m);
root = n/2;
for (int i = 1; i < n; i++) {
int x = getint(),y = getint();
v[x].push_back(y);
v[y].push_back(x);
}
L[root] = 1; fa[root][0] = 0;
dfs(root,0);
m -= (n-1);
while (m--) {
int x = getint(),y = getint();
int Lca = LCA(x,y);
++pass[x]; ++pass[y];
pass[Lca] -= 2;
}
while (!Q.empty()) {
int k = Q.front(); Q.pop();
pass[fa[k][0]] += pass[k];
--son[fa[k][0]];
if (!son[fa[k][0]]) Q.push(fa[k][0]);
}
int ans = ~0U>>1;
for (int i = 1; i <= n; i++) {
if (i != root)
ans = min(ans,pass[i] + 1);
v[i].clear();
}
printf("%d\n",ans);
}
return 0;
}
T2:
现场傻逼
题目的数据等于告诉你每个吸血鬼的度数(特判吸血鬼始祖)
度数不符合就直接输出-1了
至于剩下部分,,反正你每个点的每个度数都是要填的
所以度数为1的吸血鬼显然都是叶子节点
我们需要构造一条最长的链
度数为1的显然只能做端点
于是,将所有度数不为一的吸血鬼连起来
好的,一个for
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2020;
int T,n,m,ans,a[maxn];
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("vampire.in","r",stdin);
freopen("vampire.out","w",stdout);
#endif
cin >> T;
while (T--) {
scanf("%d",&n);
int tot; tot = ans = 0;
for (int i = 1; i <= n; i++) scanf("%d",&a[i]),tot += a[i];
if (tot - n + 2 != n) {
printf("-1\n");
continue;
}
for (int i = 1; i <= n; i++) if (a[i] >= 2) ++ans;
printf("%d\n",ans+1);
}
return 0;
}
T3:
f[i][j][k1][k2]:当前剩下第i到第j棵树,第i棵树的左边的树倒下的方向是k1,第j棵树右边的树倒下的方向是k2,期望覆盖长度
g[i][j][k1][k2]:状态ijk1k2发生的概率(用加法原理转移即可)
总之转移的时候记得乘上概率(一开始忘了,简直傻逼)
2000*2000*2*2的话,开个这么大的double数组空间吃紧
就用类似内存池的东西存下后面状态的更新数据(详见代码吧)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2020;
const int maxm = 100100;
typedef double DB;
struct Com{
int pos,L,R,from; DB Add,G;
Com(int _pos = 0,int _L = 0,int _R = 0,int _from = 0,DB _Add = 0,DB _G = 0) {
pos = _pos; L = _L; R = _R; from = _from; Add = _Add; G = _G;
}
}Comder[maxm];
int n,h,cur,pos[maxn],Left[maxn],Right[maxn],
cnt,pool[maxm],tail[maxn];
DB ans,p,q,f[maxn][2][2],g[maxn][2][2];
void Add(int i,int j,int l,int r,DB va,DB GG)
{
int pos = pool[cnt--];
Comder[pos] = Com(j,l,r,tail[i],va,GG);
tail[i] = pos;
}
void Work(int i,int j,int l,int r)
{
int disl = pos[i] - pos[i-1];
if (l == 1) disl -= h;
if (disl > h) disl = h;
DB DISL = disl; DISL *= g[j][l][r];
if (i == j) ans += 0.5*p*(f[j][l][r] + DISL);
else Add(i+1,j,0,r,0.5*p*(f[j][l][r] + DISL),0.5*p*g[j][l][r]);
int disr = pos[j+1] - pos[j];
if (r == 0) disr -= h;
if (disr > h) disr = h;
DB DISR = disr; DISR *= g[j][l][r];
if (i == j) ans+= 0.5*q*(f[j][l][r] + DISR);
else f[j-1][l][1] += 0.5*q*(f[j][l][r] + DISR),g[j-1][l][1] += 0.5*q*g[j][l][r];
if (Right[i] <= j) {
int dis = pos[Right[i]-1] - pos[i] + h;
DB DIS = dis; DIS *= g[j][l][r];
Add(Right[i],j,1,r,0.5*q*(f[j][l][r]+DIS),0.5*q*g[j][l][r]);
}
else {
int dis = pos[j] - pos[i] + disr;
DB DIS = dis; DIS *= g[j][l][r];
ans += 0.5*q*(f[j][l][r] + DIS);
}
if (Left[j] >= i) {
int dis = pos[j] - pos[Left[j]+1] + h;
DB DIS = dis; DIS *= g[j][l][r];
f[Left[j]][l][0] += 0.5*p*(f[j][l][r] + DIS);
g[Left[j]][l][0] += 0.5*p*g[j][l][r];
}
else {
int dis = pos[j] - pos[i] + disl;
DB DIS = dis; DIS *= g[j][l][r];
ans += 0.5*p*(f[j][l][r] + DIS);
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
//freopen("test.txt","w",stdout);
#else
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
#endif
cin >> n >> h; scanf("%lf",&p); q = 1.00 - p;
for (int i = 1; i <= n; i++) scanf("%d",&pos[i]);
sort(pos + 1,pos + n + 1);
pos[0] = -1E9; pos[n+1] = 1E9;
for (int i = 1; i <= n; i++) {
int now = i;
for (int j = i; j > 1; j--) {
if (pos[j] - pos[j-1] >= h) break;
--now;
}
Left[i] = now - 1; now = i;
for (int j = i; j < n; j++) {
if (pos[j+1] - pos[j] >= h) break;
++now;
}
Right[i] = now + 1;
}
for (int i = 1; i < maxm; i++) pool[i] = i; cnt = maxm - 1;
f[n][0][0] = 0;
g[n][0][0] = 1;
Work(1,n,0,0);
for (int i = 1; i <= n; i++) {
for (int j = tail[i]; j; j = Comder[j].from) {
Com k = Comder[j];
f[k.pos][k.L][k.R] += k.Add;
g[k.pos][k.L][k.R] += k.G;
pool[++cnt] = j;
}
for (int j = n; j >= i; j--)
for (int l = 0; l < 2; l++)
for (int r = 0; r < 2; r++)
if (f[j][l][r] > 0)
Work(i,j,l,r);
for (int j = i; j <= n; j++)
for (int l = 0; l < 2; l++)
for (int r = 0; r < 2; r++) {
//printf("%d %d %d %d %lf\n",i,j,l,r,f[j][l][r]);
f[j][l][r] = 0.00;
g[j][l][r] = 0.00;
}
}
printf("%.3lf",ans);
return 0;
}