2013 icpc 杭州 (5.23)
阿新 • • 發佈:2019-02-16
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;
}