您的位置:首页 > Web前端

2015 ACM/ICPC Asia Regional Hefei Online

2015-09-30 19:30 363 查看
A-Monitor the Alpacas(hdu 5484)

先给n个点,再给m个点,要从m个点中选出最少的点使得这m个点形成的凸包包含这n个点。因为m比较少,所以我们可以先对n个点求凸包,然后再判断m个点形成的线段是否和凸包相交。然后就得到了各个点可以相连的情况。于是再跑个最小环就是答案了。暴力点可以用floyd。

B-The Relationship in Club(hdu5485)

二分图染色计数。g(n)表示n个点任何满足的二分图有多少种可能。f(n)表示n个点形成联通的二分图的种数。然后求f(n)的时候,需要固定1点在X部。然后根据f(n)就可以同样固定1点在X部进行dp求解了。

详见_

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1111;
const int MOD = 105225319;

int g[maxn], f[maxn];
int dp[maxn];
int c[maxn][maxn], p2[maxn * maxn];

int n, m;

void init()
{
p2[0] = 1; c[0][0] = 1;
for(int i = 1; i < maxn; i ++)
{
c[i][0] = c[i][i] = 1;
for(int j = 1; j < i; j ++)
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
}
}

int inv2 = (MOD + 1) / 2;

void solve()
{
if(n == 1)
{
puts("0");
return ;
}
for(int i = 1; i <= n * n; i ++)
p2[i] = 1ll * p2[i - 1] * (m + 1) % MOD;

for(int i = 0; i <= n; i ++)
{
g[i] = 0;
for(int j = 0; j <= i; j ++)
g[i] = (g[i] + 1ll * c[i][j] * p2[j * (i - j)] % MOD) % MOD;
}
f[0] = 0; f[1] = 1;
for(int i = 1; i <= n; i ++)
{
f[i] = 1ll * g[i] * inv2 % MOD;
for(int j = 1; j <= i - 1; j ++)
{
f[i] = (f[i] + MOD - 1ll * c[i - 1][j - 1] * f[j] % MOD * g[i - j] % MOD) % MOD;
}
}
CLR(dp, 0); dp[0] = 1;
LL ans = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= i; j ++)
dp[i] = (dp[i]+ 1ll * f[j] * c[i - 1][j - 1] % MOD * dp[i - j] % MOD) % MOD;
}
printf("%d\n", dp
);
}

int main()
{
init();
int T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d%d", &n, &m);
printf("Case #%d: ", cas ++);
solve();
}
return 0;
}


C-Difference of Clustering(hdu 5486)
这题暴力左右两边枚举就可以了。需要用链表,开n个vector会MLE。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1000010;
map<int, int> x, y;

int heada[maxn], headb[maxn];
int nexta[maxn], nextb[maxn];
int vala[maxn], valb[maxn];

int top1, top2;
int sza, szb;
int l[maxn];
int r[maxn];
int sizea[maxn], sizeb[maxn];

int vis[maxn];

vector<int> tmp;

int main(){
int n, t, cas = 1;
cin >> t;
while(t --) {
scanf("%d", &n);
x.clear();
y.clear();
top1 = 0, top2 = 0;
sza = szb = 0;
for(int i = 0; i < n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
int tgt1, tgt2;

if(x.count(u) == 0) {
x[u] = tgt1 = top1;
heada[top1] = -1;
sizea[top1] = 0;
top1 ++;
}else{
tgt1 = x[u];
}
nexta[sza] = heada[tgt1];
vala[sza] = i;
heada[tgt1] = sza ++;
sizea[tgt1] ++;

l[i] = tgt1;

if(y.count(v) == 0) {
y[v] = tgt2 = top2;
headb[top2] = -1;
sizeb[top2] = 0;
top2 ++;
}else{
tgt2 = y[v];
}

nextb[szb] = headb[tgt2];
valb[szb] = i;
headb[tgt2] = szb ++;
sizeb[tgt2] ++;
r[i] = tgt2;
}

int ansSplits = 0, ansMerges = 0, ansOne = 0;
for(int i = 0; i < top1; i ++) {
int rad = rand();
tmp.clear();
for(int jj = heada[i]; ~jj; jj = nexta[jj]) {
int id = vala[jj];
if(vis[r[id]] == rad) continue;
tmp.push_back(r[id]);
vis[r[id]] = rad;
}
if(tmp.size() > 1) {
int sum = 0;
for(int j = 0; j < tmp.size(); j ++) {
sum += sizeb[tmp[j]];
}
if(sum == sizea[i]) ansSplits ++;
}else{
int sum = sizeb[tmp[0]];
if(sum == sizea[i]) ansOne ++;
}
}
for(int i = 0; i < top2; i ++) {
int rad = rand();
tmp.clear();
for(int jj = headb[i]; ~jj; jj = nextb[jj]) {
int id = valb[jj];
if(vis[l[id]] == rad) continue;
tmp.push_back(l[id]);
vis[l[id]] = rad;
}
if(tmp.size() > 1) {
int sum = 0;
for(int j = 0; j < tmp.size(); j ++) {
sum += sizea[tmp[j]];
}
if(sum == sizeb[i]) ansMerges ++;
}
}
printf("Case #%d: ", cas ++);
printf("%d %d %d\n", ansSplits, ansMerges, ansOne);
}
return 0;
}


D-Difference of Languages(hdu 5487)

这题也是个暴力,因为两个DFA都只有1000个状态,所以从0 0状态开始广搜就可以了。需要注意的是,一个能走,另一个不能走也可能产生最短解。这个稍微处理一下就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 1010;

int dp[maxn][maxn];
pair<int, int> last[maxn][maxn];

int mp1[maxn][26], mp2[maxn][26];
bool ed1[maxn], ed2[maxn];

void dfs(int x, int y)
{
if(x == 0 && y == 0) return ;
dfs(last[x][y].xx, last[x][y].yy);
putchar(dp[x][y] + 'a');
}

int n1, n2;

void solve()
{
queue<pair<int, int> > Q;
Q.push(MP(0, 0));
if(ed1[0] != ed2[0])
{
puts("");
return ;
}
CLR(dp, -1); dp[0][0] = 27;
while(!Q.empty())
{
pair<int, int> u = Q.front(); Q.pop();
for(int i = 0; i < 26; i ++)
{
int vx = mp1[u.xx][i], vy = mp2[u.yy][i];
if(vx == -1 && vy == -1) continue;
if(vx == -1) vx = n1;
if(vy == -1) vy = n2;
if(dp[vx][vy] != -1) continue;
dp[vx][vy] = i;
last[vx][vy] = u;
if(ed1[vx] != ed2[vy])
{
dfs(vx, vy); putchar('\n');
return ;
}
Q.push(MP(vx, vy));
}
}
puts("0");
}

int main()
{
int T, cas = 1; scanf("%d", &T);
while(T --)
{
int n, m, k;
CLR(mp1, -1); CLR(ed1, false);
scanf("%d%d%d", &n, &m, &k);
n1 = n;
for(int i = 0; i < k; i ++)
{
int u; scanf("%d", &u);
ed1[u] = true;
}
for(int i = 0; i < m; i ++)
{
int u, v; char o[4];
scanf("%d%d%s", &u, &v, o);
mp1[u][o[0] - 'a'] = v;
}
CLR(mp2, -1); CLR(ed2, false);
scanf("%d%d%d", &n, &m, &k);
n2 = n;
for(int i = 0; i < k; i ++)
{
int u; scanf("%d", &u);
ed2[u] = true;
}
for(int i = 0; i < m; i ++)
{
int u, v; char o[4];
scanf("%d%d%s", &u, &v, o);
mp2[u][o[0] - 'a'] = v;
}
printf("Case #%d: ", cas ++);
solve();
}
return 0;
}


E-Shape

这题不会。

F-Removed Interval(hdu 5489)

这题我脑抽了,写了一个可持久化线段树。而且比赛的时候无线脑抽,导致上来就发现可以敲,然后一个多小时才过掉。这题只需要维护每个位置作为LIS开始位置的长度,然后可以用树状数组,线段树,可持久化线段树之类的简单数据结构维护一下每个值作为LIS最后一个位置的最长长度就好了。然后枚举到i的时候,就看看i-L-1之前比当前值小的LIS最大值就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
//#define lson l, m, rt << 1
//#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;
const int maxm = 20*maxn;

int n, L, m, tot;
int a[maxn], t[maxn];
int T[maxm], lson[maxm], rson[maxm], c[maxm];

void init_Hash()
{
for(int i = 1; i <= n; i ++)
t[i] = a[i];
sort(t + 1, t + 1 + n);
m = unique(t + 1, t + n + 1) - t - 1;
}

int build(int l, int r)
{
int root = tot ++;
c[root] = 0;
if(l != r)
{
int mid = (l + r) >> 1;
lson[root] = build(l, mid);
rson[root] = build(mid + 1, r);
}
return root;
}

int Hash(int x)
{
return lower_bound(t + 1, t + m + 1, x) - t;
}

void up(int rt)
{
c[rt] = max(c[lson[rt]], c[rson[rt]]);
}

int query(int rt, int L, int R, int l, int r)
{
if(L <= l && r <= R)
{
return c[rt];
}
int m = (l + r) >> 1;
int ret = 0;
if(L <= m) ret = max(ret, query(lson[rt], L, R, l, m));
if(R > m) ret = max(ret, query(rson[rt], L, R, m + 1, r));
return ret;
}

int update(int rt, int pos, int val, int l, int r)
{
int root = tot ++;
if(l == r)
{
c[root] = val;
return root;
}
int m = (l + r) >> 1;
lson[root] = lson[rt];
rson[root] = rson[rt];
if(pos <= m) lson[root] = update(lson[rt], pos, val, l, m);
else rson[root] = update(rson[rt], pos, val, m + 1, r);
up(root);
return root;
}

int b[maxn], o[maxn];
#define INF 0x3f3f3f3f

void gao()
{
CLR(o, INF);
for(int i = n; i > 0; i --)
{
int tmp = lower_bound(o + 1, o + n + 1, b[i]) - o;
o[tmp] = b[i];
b[i] = tmp;
}
}

int main()
{
int cas = 1, Tt;
scanf("%d", &Tt);
while(Tt --)
{
tot = 0;
scanf("%d%d", &n, &L);
for(int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
}
init_Hash();
T[0] = build(1, m);
for(int i = 1; i <= n; i ++)
{
int pos = Hash(a[i]); a[i] = pos;
b[i] = m + 1 - pos;
int val = 0;
if(pos > 1) val = query(T[i - 1], 1, pos - 1, 1, m);
T[i] = update(T[i - 1], pos, val + 1, 1, m);
}
gao();
int ans = query(T[n - L], 1, m, 1, m);
for(int i = L + 1; i <= n; i ++)
{
int tmp = 0;
if(a[i] > 1) tmp = query(T[i - L - 1], 1, a[i] - 1, 1, m);
ans = max(ans, tmp + b[i]);
}
printf("Case #%d: %d\n", cas ++, ans);
}
return 0;
}


G-Simple Matrix(hdu 5490)
这题,对于位置i, j上的一个常数v来说,对n, m位置的答案贡献为 v * C(n - i + m - j, n - i),这个很显然。然后对于每一排的等比数列来说,计算到下一排仍然是等比数列+贡献一个常数。然后对于初始的等差数列,也可以根据常数贡献的方法去算。然后答案就很明显了。然后因为常数贡献的位置只有第一列和第二列,所以可以初始计算出一个组合数后,下面用递推式求出需要的组合数就好了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 10100;
const int MOD = 1000000007;

LL Powmod(LL a, int n)
{
LL ret = 1;
a = (a + MOD) % MOD;
while(n)
{
if(n & 1) ret = ret * a % MOD;
a = a * a % MOD;
n >>= 1;
}
return ret;
}

int a, d, b, q, n, m;

LL C(LL n, int m)
{
LL ret = 1;
for(int i = 0; i < m; i ++)
{
ret = ret * (n - i) % MOD * Powmod(i + 1, MOD - 2) % MOD;
}
return ret;
}

void solve()
{
LL ans = 0;
if(n == 0)
{
if(m == 0)
{
puts("0");
return ;
}
ans = 1ll * b * Powmod(q, m - 1) % MOD;
printf("%I64d\n", ans);
return ;
}
if(m == 0)
{
ans = a + 1ll * d * (n - 1) % MOD;
printf("%I64d\n", ans % MOD);
return ;
}
if(q==0)
{
LL x = C(n + m - 2, n - 1);
ans = x * b % MOD;
b = 0;
q = 1;
}
LL X = C(n + m - 1, n - 1);
int bb = b, qq = Powmod(q - 1, MOD - 2);
for(int i = 1; i <= n; i ++)
{
LL tmp = 1ll * b * qq % MOD;
LL Y = Powmod(n + m - i, MOD - 2);
tmp = tmp * X % MOD * Y % MOD * m % MOD;
b = 1ll * b * q % MOD * qq% MOD;
ans = (ans + a * X % MOD) % MOD;
ans = (ans + MOD - tmp) % MOD;
X = X * (n - i) % MOD * Y % MOD;
a = d;
}
if(q == 1)
{
X = C(n + m - 1, n);
ans = (ans + X * bb % MOD) % MOD;
printf("%I64d\n", ans);
return ;
}
ans = (ans + b * Powmod(q, m - 1) % MOD) % MOD;
printf("%I64d\n", ans);
}

int main()
{
int T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d%d%d%d%d%d", &b, &q, &a, &d, &n, &m);
printf("Case #%d: ", cas ++);
solve();
}
return 0;
}


H-The Next(hdu 5491)

据说是水题?

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn=111111;

int s[maxn];

int main(){
int t, cas = 1;
LL d;
int s1, s2;
cin >> t;
while(t --) {
scanf("%I64d%d%d", &d, &s1, &s2);
int now = 0;
int cnt = 0;
while(d) {
if(d&1)s[now] = 1, cnt ++;
else s[now] = 0;
now ++;
d >>= 1;
}
s[now] = 0;
if(cnt != s2) {
int pos = -1;
for(int i = 0; i <= now; i ++) {
if(s[i] == 0) {
cnt ++;
pos = i;
s[i] = 1;
break;
}
}
for(int i = pos; i <= now; i ++) {
if(s[i] == 1) s1 --;
}
int tmp = max(0, s1);
for(int i = 0; i < pos; i ++) {
if(tmp) s[i] = 1, tmp --;
else s[i] = 0;
}
}else{
int pos = -1;
bool ok = false;
for(int i = 0; i <= now; i ++) {
if(s[i] == 0 && ok) {
cnt ++;
pos = i;
s[i] = 1;
break;
}
if(s[i] == 1) {
ok = true;
}
}
for(int i = pos; i <= now; i ++) {
if(s[i] == 1) s1 --;
}
int tmp = max(0, s1);
for(int i = 0; i < pos; i ++) {
if(tmp) s[i] = 1, tmp --;
else s[i] = 0;
}

}

LL ans = 0;
for(int i = now; i >= 0; i --) {
ans = (ans << 1) | s[i];
}
printf("Case #%d: ", cas ++);
printf("%I64d\n", ans);
}
return 0;
}


I-Find a path(hdu 5492)

把方差式子变换一下,然后把和作为状态暴力dp即可。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 35;
const int inf = 0x3f3f3f3f;

int s[maxn][maxn];
int dp[maxn][maxn][60*30*2];

int main(){
int t, cas = 1, n, m;
cin >> t;
while(t --) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
scanf("%d", &s[i][j]);
}
}
memset(dp, inf, sizeof dp);

dp[1][1][s[1][1]] = s[1][1] * s[1][1];

for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
for(int k = 0; k <= 1800; k ++) {
if(dp[i][j][k] == inf) continue;
dp[i][j + 1][k + s[i][j + 1]] = min(dp[i][j + 1][k + s[i][j + 1]], dp[i][j][k] + s[i][j + 1] * s[i][j + 1]);
dp[i + 1][j][k + s[i + 1][j]] = min(dp[i + 1][j][k + s[i + 1][j]], dp[i][j][k] + s[i + 1][j] * s[i + 1][j]);
}
}
}

LL ans = inf;
for(int i = 0; i <= 1800; i ++) {
ans = min(ans, (n + m - 1ll) * dp
[m][i] - i * i);
}
printf("Case #%d: ", cas ++);
printf("%I64d\n", ans);
}
return 0;
}


J-Queue(hdu 5493)

首先贪心,如果顺序放的话,对于每个数都可以确定出对称的两个位置,由于要字典序最小的。显然我们需要把这个数放在前面,然后就用线段树求一下每次要放的位置就好了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define xx first
#define yy second
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;

int sum[maxn<<2];

int n;

void PushUp(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void build(int l = 1, int r = n, int rt = 1)
{
if(l == r)
{
sum[rt] = 0;
return ;
}
int m=(l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int p, int l = 1, int r = n, int rt = 1)
{
if(l == r)
{
sum[rt] = 1;
return ;
}
int m = (l + r) >> 1;
if (p <= m) update(p, lson);
else update(p ,rson);
PushUp(rt);
}

int query(int p, int l = 1, int r = n, int rt = 1)
{
if(l == r)
{
return l;
}
int m = (l + r) >> 1;
int lsz = m - l + 1 - sum[rt << 1];
if (lsz >= p) return query(p , lson);
return query(p - lsz, rson);
}

int a[maxn], r[maxn], b[maxn], ans[maxn];

bool cmp(int i, int j)
{
return a[i] < a[j];
}

void solve()
{
sort(b + 1, b + n + 1, cmp);
int tot = n;
build();
for(int i = 1; i <= n; i ++)
{
int id = b[i];
int p = min(r[id] + 1, tot - r[id]);
if(p <= 0)
{
puts("impossible");
return ;
}
int pos = query(p);
ans[pos] = a[id];
update(pos);
tot --;
}
for(int i = 1; i <= n; i ++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}

int main()
{
int T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%d%d", &a[i], &r[i]);
b[i] = i;
}
printf("Case #%d: ", cas ++);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  比赛总结