1. 程式人生 > >2013 icpc 杭州 (5.23)

2013 icpc 杭州 (5.23)

A - Lights Against Dudely

題解

暴力列舉所有的方法,然後去check,更新答案;

程式碼

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second #define lson l,mid,o<<1 #define rson mid+1,r,o<<1|1 using namespace std; typedef long long LL; typedef unsigned long long uLL; typedef pair<int, int> P; typedef pair<int, P> PII; const LL INF = 0x3f3f3f3f; const int N = 1e5 + 10; const LL mod = 1e9 + 7; const
double PI=acos(-1); inline int ab(int x){return x < 0 ? -x : x;} inline int mm(int x, int p){return x >= p ? x - p : x < 0 ? x + p : x;} char mp[210][210]; bool vis[210][210]; P node[20]; P now[20]; bool change(int id, int x, int y){ if(id == 0){ if(mp[x - 1][y] == '#' || mp[x][y + 1] == '#'
) return false; vis[x - 1][y] = vis[x][y + 1] = true; } else if(id == 1){ if(mp[x - 1][y] == '#' || mp[x][y - 1] == '#') return false; vis[x - 1][y] = vis[x][y - 1] = true; } else if(id == 2){ if(mp[x][y - 1] == '#' || mp[x + 1][y] == '#') return false; vis[x][y - 1] = vis[x + 1][y] = true; } else if(id == 3){ if(mp[x][y + 1] == '#' || mp[x + 1][y] == '#') return false; vis[x][y + 1] = vis[x + 1][y] = true; } vis[x][y] = true; return true; } int main() { int n, m; while(scanf("%d%d", &n, &m)){ if(!n && !m) break; for(int i = 1; i <= n; ++i) scanf("%s", mp[i] + 1); for(int i = 0; i <= m + 1; ++i) mp[0][i] = mp[n + 1][i] = '.'; for(int i = 1; i <= n; ++i) mp[i][0] = mp[i][m + 1] = '.'; int cnt = 0, tot = 0; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(mp[i][j] == '.') node[cnt++] = {i, j}; if(!cnt){ printf("0\n"); continue; } int ans = INF; bool flag = true; for(int i = 0; i < cnt; ++i) vis[node[i].fi][node[i].se] = false; for(int i = 0; i < (1 << cnt); ++i){ tot = 0; for(int j = 0; j < cnt; ++j) if(i & (1 << j)) now[tot++] = node[j]; for(int j = 0; j < tot; ++j){ for(int h = 0; h < 4; ++h){ if(!change(h, now[j].fi, now[j].se)) continue; flag = true; for(int z = 0; z < tot; ++z){ if(z == j) continue; if(!change(0, now[z].fi, now[z].se)) flag = false; } if(flag) for(int z = 0; z < cnt; ++z) if(!vis[node[z].fi][node[z].se]) flag = false; if(flag) ans = min(ans, tot); for(int z = 0; z < cnt; ++z) vis[node[z].fi][node[z].se] = false; } } } if(ans == INF) printf("-1\n"); else printf("%d\n", ans); } return 0; }

B - Stealing Harry Potter’s Precious

C - Zhuge Liang’s Password

D - Problem of Apollonius

E - Random Number Generator

F - Infinite Go

G - Ants

題解

首先可以求出每一位置作為起點的最小的代價並加入到一個集合中,那麼這個集合中的最小值一定是所有點對的最小值,假設u出發得到了最小值,那麼先將這個最小值刪除然後將這個點出發的第次小值加入到佇列,然後就一直這樣操作下去就可以了

程式碼

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, LL> P;
typedef pair<LL, int> PI;
const LL INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int M = 62;
const int NM = N * M;
const LL mod = 1e9 + 7;
const double Pi=acos(-1);
inline int ab(int x){return x < 0 ? -x : x;}
inline int mm(int x, int p){return x >= p ? x - p : x < 0 ? x + p : x;}


vector<P>son[N];
LL v[N];
LL ans[N << 1];
int cnt[N];
priority_queue<PI>que;
void dfs(int o, int fa){
    for(auto it : son[o])   if(it.fi != fa)    v[it.fi] = v[o] ^ it.se , dfs(it.fi, o);
}
int node[NM], tot, root, net[NM][2];
int new_node(){
    ++tot;
    node[tot] = net[tot][0] = net[tot][1] = 0;
    return tot;
}
void add(LL x){
    int now = root, u;
    for(int i = 60; i >= 0; --i){
        u = x >> i & 1;
        if(!net[now][u])    net[now][u] = new_node();
        now = net[now][u];
        node[now]++;
    }
}
LL query(LL x, int k){
    int now = root, u;
    LL ret = 0;
    for(int i = 60; i >= 0; --i){
        u = x >> i & 1;
        if(node[net[now][!u]] > k)  now = net[now][!u], ret |= (1ll << i);
        else    k -= node[net[now][!u]], now = net[now][u];
    }
    return ret;
}
int main()
{
    int n;
    while(scanf("%d", &n)){
        if(!n)  break;
        int u, vv;
        LL w;
        for(int i = 1; i <= n; ++i) son[i].clear();
        for(int i = 1; i < n; ++i){
            scanf("%d%d%lld", &u, &vv, &w);
            son[u].push_back({vv, w});
            son[vv].push_back({u, w});
        }
        v[1] = 0, dfs(1, 1);
        tot = 0;    root = new_node();
        for(int i = 1; i <= n; ++i) add(v[i]);
        while(!que.empty()) que.pop();
        for(int i = 1; i <= n; ++i) cnt[i] = 0, que.push({query(v[i], cnt[i]), i});
        PI now;
        int en = min(n * 1ll * (n - 1), 200000ll);
        for(int i = 1; i <= en; ++i){
            now = que.top();    que.pop();
            ans[i] = now.fi;
            cnt[now.se]++;
            if(cnt[now.se] < n - 1) que.push({query(v[now.se], cnt[now.se]), now.se});
        }
        int m;
        scanf("%d", &m);
        for(int i = 1; i <= m; ++i){
            scanf("%d", &u);
            if(u <= en) printf("%lld\n", ans[u]);
            else    puts("-1");
        }
    }
    return 0;
}

H - Rabbit Kingdom

題解

首先可以預處理出來每一個數的互質範圍,然後將詢問按l排序,那麼對於一個詢問L, R
我們把所有 位置大於等於L,並且互質範圍的左端點小於L的點 在其位置x處加1, 右端點處減1
這樣只要統計L-R的區間和就可以了

程式碼

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> P;
typedef pair<int, P> PII;
const LL INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
const LL mod = 1e9 + 7;
const double PI=acos(-1);
inline int ab(int x){return x < 0 ? -x : x;}
inline int mm(int x, int p){return x >= p ? x - p : x < 0 ? x + p : x;}


bool check[N];
vector<int>vc[N];
void init()
{
    memset(check, false, sizeof(check));
    for(int i = 2; i < N; ++i){
        if(check[i])    continue;
        for(int j = i; j < N; j += i)
            vc[j].push_back(i), check[j] = true;
    }
}
int per[N];
int l[N], r[N];
int v[N];
int n, m;
vector<int>que[N];
vector<P>qer[N];
int ans[N];
int node[N];
int sum(int x){
    int ret = 0;
    for(; x; x -= ( x & (-x)))  ret += node[x];
    return ret;
}
void update(int x, int n, int d){
    for(; x <= n; x += (x & (-x)))  node[x] += d;
}
int main()
{
    init();
    while(scanf("%d%d", &n, &m)){
        if(!n && !m)    break;
        for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
        for(int i = 0; i <= n; ++i) que[i].clear(), qer[i].clear();
        memset(per, 0, sizeof per);
        for(int i = 1; i <= n; ++i){
            l[i] = 0;
            for(auto it : vc[v[i]])
                l[i] = max(l[i], per[it]), per[it] = i;
            que[l[i]].push_back(i);
        }
        memset(per, INF, sizeof per), r[0] = INF;
        for(int i = n; i >= 1; --i){
            r[i] = INF;
            for(auto it : vc[v[i]])
                r[i] = min(r[i], per[it]),  per[it] = i;
        }
        int ll, rr;
        for(int i = 1; i <= m; ++i){
            scanf("%d%d", &ll, &rr);
            qer[ll].push_back({rr, i});
        }
        memset(node, 0, sizeof node);
        for(int i = 1; i <= n; ++i){
            for(auto it : que[i - 1]){
                update(it, n, 1);
                if(r[it] <= n)   update(r[it], n, -1);
            }
            if(r[i - 1] <= n)   update(r[i - 1], n, 1);
            for(auto it : qer[i])
                ans[it.se] = sum(it.fi) - sum(i - 1);
        }
        for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    }
    return 0;
}

I - Gems Fight!

題解

這一題就是一個狀壓的爆搜,然後每一個狀態表示當前達到這個狀態的人的說能獲得的最大值,這樣就可以只開一維了,開兩維會tle

程式碼

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> P;
typedef pair<int, P> PII;
const LL INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
const LL mod = 1e9 + 7;
const double PI=acos(-1);
inline int ab(int x){return x < 0 ? -x : x;}
inline int mm(int x, int p){return x >= p ? x - p : x < 0 ? x + p : x;}


int dp[1 << 21];
int num[1 << 21];
int cnt[30][10];
int en, n, s, m;
void dfs(int tmp){
    int to, add;
    for(int i = 0; i < n; ++i){
        if(tmp & (1 << i))  continue;
        to = tmp | (1 << i), add = num[to] - num[tmp];
        if(dp[to] == -INF)    dfs(to);
        if(add) dp[tmp] = max(dp[tmp], dp[to] + add);
        else    dp[tmp] = max(dp[tmp], -dp[to]);
    }
}
int main()
{
    while(scanf("%d%d%d", &m, &n, &s)){
        if(!n && !m && !s)    break;
        for(int i = 0; i < (1 << n); ++i)   dp[i] = -INF;
        en = (1 << n) - 1;
        int k, x;
        memset(cnt, 0, sizeof cnt);
        for(int i = 0; i < n; ++i){
            scanf("%d", &k);
            while(k--){
                scanf("%d", &x);
                cnt[i][x]++;
            }
        }
        memset(num, 0, sizeof num);
        int tot[10];
        for(int i = 1; i < (1 << n); ++i){
            memset(tot, 0, sizeof tot);
            for(int j = 0; j < n; ++j){
                if((i >> j) & 1){
                    for(int h = 1; h <= m; ++h){
                        tot[h] += cnt[j][h];
                        while(tot[h] >= s){
                            tot[h] -= s;
                            num[i]++;
                        }
                    }
                }
            }
        }
        dp[en] = 0;
        dfs(0);
        printf("%d\n", dp[0]);
    }
    return 0;
}

J - Tower Defense

K - Candy Factory