您的位置:首页 > 其它

20150807解题报告

2015-08-08 22:36 274 查看

【T1】way

写了个hash+map的优美状压,改写成meet in the middle可以满分。【我说的是人话吗?】

100%题解:对于一条哈密尔顿回路,除了1外另找一个点i则该路径为1-……-i-……-1。记前半段除了1与i长度为n1,后半段为n2,那么如果确定了i,只要满足前半段与后半段经过的点不重复(除1)且路径总长为l。具体来说就是就是枚举一个点i,用P(n-2,n1)的时间枚举前半段的所有情况,用hash记下来(拉链,c++用map估计会T),再用P(n-2,n2)的时间枚举后半段的所有情况,并在hash中找到与之对应的前半段,统计进答案中。这样的话复杂度为(n-1)*(P(n-2,n1)+P(n-2,n2))*(hash均摊复杂度),显然n1取trunc(n/2)最优。

70分代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long

typedef map<int, int> mp;
typedef mp::iterator mpit;
const int maxn = 20;
const int NN = 17000;
int a[maxn][maxn];
int vis[maxn];
int n, l, cnt;
mp f[NN][maxn];

void dfs(int dep, int x, int now) {
vis[x] = 1;
if (dep == n) {
if (now + a[x][0] == l) cnt++;
}
else
rep(i, 1, n-1) {
if (vis[i]) continue;
if (now + a[x][i] > l) continue;
dfs(dep + 1, i, now + a[x][i]);
}
vis[x] = 0;
}

int main() {
// freopen("way.in", "r", stdin);
// freopen("way.out", "w", stdout);
scanf("%d%d", &n, &l);
rep(i, 0, n-1) rep(j, 0, n-1) scanf("%d", &a[i][j]);
cnt = 0;
if (n <= 11) {
memset(vis, 0, sizeof(vis));
dfs(1, 0, 0);
printf("%d\n", cnt);
} else {
int jj = 0;
for(int i = 2; i <= (1 << (n - 1)) ; i <<= 1) {
jj++;
f[i][jj][a[0][jj]] = 1;
}
for(int i = 2; i <= (1 << n) - 2; i += 2) {
for(int j = 1; j <= n-1; j++) {
//cout << i << ' ' << j << ' ' << (i & (1<<j) )<< endl;
if ((i & (1<<j))== 0) continue;
for(int k = 1; k <= n-1; k++) {
if (k == j) continue;
int state = i - (1 << j);
for(mpit it = f[state][k].begin(); it != f[state][k].end(); ++it) {
int len = it -> first;
f[i][j][len + a[k][j]] += it -> second;
}
}
}
}
int final = (1 << n) - 2;
for(int i = 1; i <= n-1; i++) {
cnt += f[final][i][l-a[i][0]];
}
printf("%d\n", cnt);
}
return 0;
}

【T2】Tree

上下两个方向树形dp,给小朋友讲做法真的好累啊。【我说的是人话吗】

100%题解:先用一遍dfs求出以1(这个点随便取)为根往下的最大长度与次大长度,再用一遍dfs求出以1(与之前的根保持一致)为根每个点的不进入该点子树的最大长度(dfs到一个点u时用u以及u的儿子的信息更新u的儿子的信息),再用每个点的三个值求每个点的答案

(附上大师的神图)



#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define red(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long

const int maxn = 200000;
struct edge {
int from, to, len, nxt;
}e[maxn];
struct dp {
int len, ch;
}f[maxn], g[maxn];
int vis[maxn], head[maxn], order[maxn], fa[maxn], dis[maxn], h[maxn], ans[maxn];
int n, tail = 0;
queue<int> q;

void addedge(int u, int v, int w) {
e[++tail].from = u;
e[tail].to = v;
e[tail].len = w;
e[tail].nxt = head[u];
head[u] = tail;
}

void bfs() {
int m = 1; order[1] = 1;
memset(vis, 0, sizeof(vis));
q.push(1); vis[1] = 1;
fa[1] = 0; dis[1] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if (vis[v]) continue;
q.push(v); vis[v] = 1;
order[++m] = v;
fa[v] = u; dis[v] = e[i].len;
}
}
}

void DP_UP() {
red(i, n, 1) {
int u = order[i], max1 = 0, max2 = 0;
f[u].len = 0; f[u].ch = 0;
g[u].len = 0; f[u].ch = 0;
for(int j = head[u]; j != -1; j = e[j].nxt) {
int v = e[j].to;
if (v == fa[u]) continue;
if (f[v].len + e[j].len > f[u].len) {
g[u].len = f[u].len;
g[u].ch = f[u].ch;
f[u].len = f[v].len + e[j].len;
f[u].ch = v;
}else if (f[v].len + e[j].len > g[u].len) {
g[u].len = f[v].len + e[j].len;
g[u].ch = v;
}
}
}
}

void DP_DOWN() {
rep(i, 1, n) {
int u = order[i];
if (u == 1) {
h[i] = 0;
continue;
}
h[u] = f[fa[u]].ch == u ? g[fa[u]].len : f[fa[u]].len;
if (h[fa[u]] > h[u]) h[u] = h[fa[u]];
h[u] += dis[u];
}
}

void Calc() {
rep(i, 1, n) {
int u = order[i];
ans[u] = f[u].len + g[u].len;
if (f[u].len + h[u] > ans[u]) ans[u] = f[u].len + h[u];
}
rep(i, 1, n) printf("%d\n", ans[i]);
}

int main() {
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);

scanf("%d", &n);
rep(i, 1, n) head[i] = -1;
rep(i, 1, n-1) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
bfs();
DP_UP();
DP_DOWN();
Calc();
return 0;
}

【T3】Photo

这dp真TMD太NB啦,还用了一次不定方程的解得个数,大师不愧数学帝啊。【我说的是人话吗?】

100%题解:



#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define red(i, a, b) for (int i = (a); i >= (b); i--)
#define ll long long

const ll mod = 1000000007;
const int maxn = 60;
const int maxp = 60;
const int maxtot = 6000;
ll dp[maxn][maxtot], c[maxtot][maxtot];
ll fac[maxp], a[maxn];
int n;
ll sum,ans;

void Calc_C() {
fac[0] = 1; c[0][0] = 1;
for(ll i = 1; i <= maxp; i++) fac[i] = fac[i-1] * i % mod;
rep(i, 1, 5000) {
c[i][0] = 1; c[i][i] = 1;
rep(j, 1, i-1) {
c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
}
}
}

int main() {
freopen("photo.in", "r", stdin);
freopen("photo.out", "w", stdout);

Calc_C();
scanf("%d", &n);
rep(i, 1, n) scanf("%I64d", &a[i]);
memset(dp, 0, sizeof(dp));
dp[1][a[1] - 1] = 1;
sum = a[1];
rep(i, 2, n) {
rep(j, 0, sum) {
if (dp[i-1][j] == 0) continue;
rep(k, 1, a[i]) {
rep(t, 0, min(j, k)) {
ll temp = dp[i-1][j] * c[j][t] % mod * c[a[i]-1][k-1] % mod * c[sum+1-j][k-t] % mod;
dp[i][j-t+a[i]-k] += temp; dp[i][j-t+a[i]-k] %= mod;
}
}
}
sum += a[i];
}
ans = dp
[0];
rep(i, 1, n) ans = ans * fac[a[i]] % mod;
cout << ans << endl;
return 0;
}


大师~~我做题一点都不愉快
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: