2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)
Posted kikokiko
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)相关的知识,希望对你有一定的参考价值。
[2018-2019 ACM-ICPC Brazil Subregional Programming Contest]
(A.Slackline Adventure)
(B.Marbles)
NIM游戏,把其中任意一个石子移动到(0,0)算赢,所以必败态为全部石子都到(1,2)和(2,1)这两个点而不是(0,0)了,跑出sg函数异或即可,注意如果出现先手直接赢的需要特判
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 111;
int n,sg[MAXN][MAXN];
bool vis[MAXN<<2];
void getsg(){
for(int i = 1; i <= 100; i++) sg[i][0] = sg[0][i] = sg[i][i] = 0;
for(int k = 1; k <= 200; k++){
for(int i = max(0,k-100); i <= min(100,k); i++){
memset(vis,0,sizeof(vis));
int j = k - i;
if(i==j) continue;
for(int u = 1; u < i; u++) if(i-u!=j) vis[sg[i-u][j]] = true;
for(int u = 1; u < j; u++) if(i!=j-u) vis[sg[i][j-u]] = true;
for(int u = 1; u < min(i,j); u++) vis[sg[i-u][j-u]] = true;
for(int u = 0; ; u++) if(!vis[u]){
sg[i][j] = u;
break;
}
}
}
}
int main(){
getsg();
scanf("%d",&n);
int res = 0;
for(int i = 1; i <= n; i++){
int x,y;
scanf("%d %d",&x,&y);
if(x==y) return puts("Y");
res^=sg[x][y];
}
puts(res?"Y":"N");
return 0;
}
(C.Pizza Cutter)
两维分开处理,离散化之后按第一维从小到大排序+树状数组统计,只要找到右端点比当前点右端点高的数量即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
const int MAXN = 2e5+7;
int n,m;
LL res;
pair<int,int> coor[MAXN];
vector<int> vec;
struct BinaryIndexedTree{
int val[MAXN];
#define lowbit(x) ((x)&-(x))
void update(int pos){
while(pos){
val[pos]++;
pos-=lowbit(pos);
}
}
int query(int pos){
int r = 0;
while(pos<MAXN){
r += val[pos];
pos+=lowbit(pos);
}
return r;
}
}BIT;
int main(){
scanf("%d %d %d %d",&n,&m,&n,&m);
for(int i = 1; i <= n; i++){
scanf("%d %d",&coor[i].first,&coor[i].second);
vec.emplace_back(coor[i].first);
vec.emplace_back(coor[i].second);
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(int i = 1; i <= n; i++){
coor[i].first = lower_bound(vec.begin(),vec.end(),coor[i].first) - vec.begin() + 1;
coor[i].second = lower_bound(vec.begin(),vec.end(),coor[i].second) - vec.begin() + 1;
}
sort(coor+1,coor+1+n);
for(int i = 1; i <= n; i++){
res += 1 + BIT.query(coor[i].second);
BIT.update(coor[i].second);
}
vec.clear();
memset(BIT.val,0,sizeof(BIT.val));
for(int i = 1; i <= m; i++){
scanf("%d %d",&coor[i].first,&coor[i].second);
vec.emplace_back(coor[i].first);
vec.emplace_back(coor[i].second);
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(int i = 1; i <= m; i++){
coor[i].first = lower_bound(vec.begin(),vec.end(),coor[i].first) - vec.begin() + 1;
coor[i].second = lower_bound(vec.begin(),vec.end(),coor[i].second) - vec.begin() + 1;
}
sort(coor+1,coor+1+m);
for(int i = 1; i <= m; i++){
res += 1 + n + BIT.query(coor[i].second);
BIT.update(coor[i].second);
}
printf("%I64d
",res+1);
return 0;
}
(D.Unraveling Monty Hall)
温暖签到
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int main(){
int n,ans=0,x;
scanf("%d",&n);
while(n--){
scanf("%d",&x);
ans += (x!=1?1:0);
}
printf("%d
",ans);
return 0;
}
(E.Enigma)
温暖签到 1e8只要跑34ms?
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e4+7;
char s[MAXN],t[MAXN];
int main(){
scanf("%s %s",s+1,t+1);
int lens = strlen(s+1);
int lent = strlen(t+1);
int cnt = 0;
for(int i = 1; i <= lens-lent+1; i++){
bool ok = true;
for(int j = i; j <= i + lent-1; j++){
if(s[j]==t[j-i+1]){
ok = false;
break;
}
}
cnt += ok ? 1: 0;
}
cout << cnt << endl;
return 0;
}
(F.Music Festival)
发现N只有10,想到状态压缩,要求最后所有stage都去过并且最后听的歌最多,考虑(f[msk][i])表示当前去过的stage位(msk)中的(1),当前时间为(i),此时听的歌最多是多少,从前面最大的转移即可,找最大可以用线段树维护,可以先离散化处理
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2222;
int n;
vector<pair<pair<int,int>,pair<int,int>>> perf;
vector<int> vec;
struct SegmentTree{
int maxx[MAXN<<2],l[MAXN<<2],r[MAXN<<2];
#define ls(rt) (rt) << 1
#define rs(rt) (rt) << 1 | 1
#define pushup(rt) maxx[rt] = max(maxx[ls(rt)],maxx[rs(rt)]);
void build(int L, int R, int rt){
l[rt] = L, r[rt] = R;
maxx[rt] = -1;
if(L+1==R) return;
int mid = (L+R) >> 1;
build(L,mid,ls(rt));
build(mid,R,rs(rt));
}
void update(int pos, int rt, int x){
if(l[rt]+1==r[rt]){
maxx[rt] = x;
return;
}
int mid = (l[rt]+r[rt]) >> 1;
if(pos<mid) update(pos,ls(rt),x);
else update(pos,rs(rt),x);
pushup(rt);
}
int query(int L, int R, int rt){
if(l[rt]>=R || L>=r[rt]) return -1;
if(L<=l[rt] && r[rt]<=R) return maxx[rt];
return max(query(L,R,ls(rt)),query(L,R,rs(rt)));
}
}ST[MAXN];
int main(){
scanf("%d",&n);
for(int i = 0; i < n; i++){
int sz;
scanf("%d",&sz);
for(int j = 0; j < sz; j++){
int l, r, o;
scanf("%d %d %d",&l,&r,&o);
perf.emplace_back(make_pair(make_pair(l,r),make_pair(o,i)));
vec.emplace_back(l);
vec.emplace_back(r);
}
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(int i = 0; i < (int)perf.size(); i++){
perf[i].first.first = lower_bound(vec.begin(),vec.end(),perf[i].first.first) - vec.begin() + 1;
perf[i].first.second = lower_bound(vec.begin(),vec.end(),perf[i].first.second) - vec.begin() + 1;
}
sort(perf.begin(),perf.end(),[](const pair<pair<int,int>,pair<int,int>> &A,const pair<pair<int,int>,pair<int,int>> &B){
return A.first.first < B.first.first;
});
for(int msk = 0; msk < (1<<n); msk++) ST[msk].build(0,MAXN,1);
ST[0].update(0,1,0);
for(auto p : perf){
for(int msk = 0; msk < (1<<n); msk++){
if(!(msk&(1<<p.second.second))) continue;
int maxx = max(ST[msk].query(0,p.first.first+1,1),ST[msk^(1<<p.second.second)].query(0,p.first.first+1,1));
if(maxx==-1) continue;
if(ST[msk].query(0,p.first.second+1,1)>=maxx+p.second.first) continue;
ST[msk].update(p.first.second,1,maxx+p.second.first);
}
}
printf("%d
",ST[(1<<n)-1].query(0,MAXN,1));
return 0;
}
(G.Gasoline)
显然二分答案之后网络流
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2222;
const int INF = 0x3f3f3f3f;
#define S 0
#define T MAXN-1
struct EDGE{
int to,cap,rev;
EDGE(){}
EDGE(int to, int cap, int rev){
this->to = to;
this->cap = cap;
this->rev = rev;
}
};
pair<pair<int,int>,int> edge[MAXN<<4];
int p,r,m,pn[MAXN],rn[MAXN],tot,rk[MAXN],iter[MAXN];
vector<EDGE> G[MAXN];
void ADDEDGE(int u, int v, int cap){
G[u].emplace_back(EDGE(v,cap,(int)G[v].size()));
G[v].emplace_back(EDGE(u,0,(int)G[u].size()-1));
}
bool BFS(){
queue<int> que;
que.push(S);
memset(rk,0,sizeof(rk));
memset(iter,0,sizeof(iter));
rk[S] = 1;
while(!que.empty()){
int u = que.front();
que.pop();
for(auto e : G[u]){
if(!e.cap||rk[e.to]) continue;
rk[e.to] = rk[u] + 1;
que.push(e.to);
}
}
return rk[T]!=0;
}
int dfs(int u, int f){
if(u==T) return f;
for(int &i = iter[u]; i < (int)G[u].size(); i++){
EDGE &e = G[u][i];
if(!e.cap||rk[e.to]!=rk[u]+1) continue;
int d = dfs(e.to,min(f,e.cap));
if(d){
e.cap -= d;
G[e.to][e.rev].cap += d;
return d;
}
}
return 0;
}
int Dinic(){
int flow = 0;
while(BFS()){
int d = dfs(S,INF);
while(d){
flow += d;
d = dfs(S,INF);
}
}
return flow;
}
bool check(int mid){
for(int i = 0; i < MAXN; i++) G[i].clear();
for(int i = 1; i <= m; i++){
if(edge[i].second>mid) continue;
ADDEDGE(edge[i].first.second,edge[i].first.first+r,INF);
}
for(int i = 1; i <= p; i++) ADDEDGE(i+r,T,pn[i]);
for(int i = 1; i <= r; i++) ADDEDGE(S,i,rn[i]);
return Dinic()==tot;
}
int work(){
int L = 1, R = 1e6;
while(L<=R){
int mid = (L+R) >> 1;
if(check(mid)) R = mid - 1;
else L = mid + 1;
}
return L>1e6?-1:L;
}
int main(){
scanf("%d %d %d",&p,&r,&m);
for(int i = 1; i <= p; i++){
scanf("%d",&pn[i]);
tot += pn[i];
}
for(int i = 1; i <= r; i++) scanf("%d",&rn[i]);
for(int i = 1; i <= m; i++) scanf("%d %d %d",&edge[i].first.first,&edge[i].first.second,&edge[i].second);
printf("%d
",work());
return 0;
}
(H.Police Hypothesis)
(I.Switches)
最多操作(2n)次,暴力判断
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
int n,m,tot,light[MAXN];
vector<int> vec[MAXN];
bool press(int p){
for(int pos : vec[p]){
if(light[pos]) tot--;
else tot++;
light[pos]^=1;
}
return !tot;
}
int main(){
scanf("%d %d",&n,&m);
int l;
scanf("%d",&l);
for(int i = 1; i <= l; i++){
int x;
scanf("%d",&x);
light[x] = 1;
tot++;
}
for(int i = 1; i <= n; i++){
int sz;
scanf("%d",&sz);
vec[i].resize(sz);
for(int j = 0; j < sz; j++) scanf("%d",&vec[i][j]);
}
for(int i = 1; i <= 2*n; i++){
if(press((i-1)%n+1)){
printf("%d
",i);
return 0;
}
}
puts("-1");
return 0;
}
(J.Joining Capitals)
(以下的Terminal点就是题中的Capital)
要求构造一棵所有的Terminal点都是叶子节点的最小斯坦纳树
(f[i][msk])表示以(i)为根节点,当前包含(msk)中(1)所表示的Terminal点的最短总长
和一般构造斯坦纳树不同的地方在于
- Terminal点不能作为合并点
- 不能用一个Terminal点扩展另一个Terminal点为根的状态
- 如果一个状态的根为Terminal点并且已经有连边,则不能扩展
注意特判(k=2)的情况,这个情况下直接连接两个Terminal点即可
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1111;
const int INF = 0x3f3f3f3f;
int n,k,st[MAXN],limit;
bool vis[MAXN];
pair<double,double> coor[MAXN];
double f[MAXN][MAXN];
queue<int> que;
double dist(const pair<double,double> &A, const pair<double,double> &B){
return sqrt((A.first-B.first)*(A.first-B.first)+(A.second-B.second)*(A.second-B.second));
}
void spfa(int msk){
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = 1; i <= n; i++){
if((u<=k&&i<=k)||(u<=k&&(msk!=st[u]))) continue;
double dis = dist(coor[i],coor[u]);
if(f[u][msk]+dis<f[i][st[i]|msk]){
f[i][st[i]|msk] = f[u][msk]+dis;
if(!vis[i]&&(st[i]|msk)==msk){
que.push(i);
vis[i] = true;
}
}
}
}
}
int main(){
scanf("%d %d",&n,&k);
for(int i = 0; i < MAXN; i++) fill(f[i],f[i]+MAXN,INF);
for(int i = 1; i <= n; i++){
scanf("%lf %lf",&coor[i].first,&coor[i].second);
if(i<=k){
st[i] = (1<<(i-1));
f[i][st[i]] = 0;
}
}
if(k==2) return printf("%.5f
",dist(coor[1],coor[2])),0;
limit = 1<<k;
for(int msk = 1; msk < limit; msk++){
for(int i = 1; i <= n; i++){
if(i<=k){
if(f[i][msk]<INF) que.push(i),vis[i] = true;
continue;
}
for(int sub = (msk-1)&msk; sub; sub = (sub-1)&msk)
if(f[i][sub]+f[i][msk^sub]<f[i][msk]) f[i][msk] = f[i][sub] + f[i][msk^sub];
if(f[i][msk]<INF) que.push(i),vis[i] = true;
}
spfa(msk);
}
printf("%.5f
",f[1][limit-1]);
return 0;
}
(K.Kepler)
由于(0,0)点必然在圆内,并且根据题意两个圆的关系只存在相交(两个不同点)和包含两个关系,又由于(x,y)比较小,(r)比较大,所以按(r)进行排序之后暴力即可,利用break跳出后续无用情况:(r_2-r_1>50sqrt2)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 150007;
int n;
struct Orbit{
double x,y,r;
bool operator < (const Orbit &rhs) const{
return r < rhs.r;
}
}orbit[MAXN];
double dist(double x1, double y1, double x2, double y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int check(int I, int J){
return abs(orbit[I].r-orbit[J].r) < dist(orbit[I].x,orbit[I].y,orbit[J].x,orbit[J].y);
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%lf %lf %lf",&orbit[i].x,&orbit[i].y,&orbit[i].r);
sort(orbit+1,orbit+1+n);
int tot = 0;
for(int i = 1; i <= n; i++){
for(int j = i+1; j <= n; j++){
if(orbit[j].r-orbit[i].r>50*sqrt(2)) break;
tot += check(i,j)*2;
if(tot>2*n){
cout << "greater" << endl;
return 0;
}
}
}
cout << tot << endl;
return 0;
}
(L.Subway Lines)
树上链交,用LCA+倍增做就行
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 1e5+7;
vector<int> G[MAXN];
int n,m,par[MAXN][20],depth[MAXN];
void dfs(int u, int f){
depth[u] = depth[f] + 1;
par[u][0] = f;
for(int i = 1; par[u][i-1]; i++) par[u][i] = par[par[u][i-1]][i-1];
for(int v : G[u]){
if(v==f) continue;
dfs(v,u);
}
}
int LCA(int u, int v){
if(depth[u]<depth[v]) swap(u,v);
for(int i = 0; depth[u]-depth[v]; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
if(u==v) return u;
for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
u = par[u][i];
v = par[v][i];
}
return par[u][0];
}
int intersect(int u, int depu, int v, int depv){
if(depu>depth[v]||depv>depth[v]) return 0;
if(depth[u]<depth[v]){
swap(u,v);
swap(depu,depv);
}
for(int i = 0; depth[u]-depth[v]; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
if(depth[u]<depu) return 0;
if(u==v) return depth[u] - max(depu,depv) + 1;
for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
u = par[u][i];
v = par[v][i];
}
return max(0,depth[u]-max(depu,depv));
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 1; i < n; i++){
int u, v;
scanf("%d %d",&u,&v);
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs(1,0);
for(int i = 1; i <= m; i++){
int ua,va,ub,vb;
scanf("%d %d %d %d",&ua,&va,&ub,&vb);
int depa = depth[LCA(ua,va)], depb = depth[LCA(ub,vb)];
printf("%d
",intersect(ua,depa,ub,depb)+intersect(ua,depa,vb,depb+1)+intersect(va,depa+1,ub,depb)+intersect(va,depa+1,vb,depb+1));
}
return 0;
}
(M.Modifying SAT)
以上是关于2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)的主要内容,如果未能解决你的问题,请参考以下文章
2018-2019 ACM-ICPC Brazil Subregional Programming Contest PART (10/13)
2018-2019 ACM-ICPC Brazil Subregional Programming Contest
gym101908 [2018-2019 ACM-ICPC Brazil Subregional Programming Contest] 题解
2018-2019 ACM-ICPC Brazil Subregional Programming Contest B. Marbles
2019-2020 ACM-ICPC Brazil Subregional Programming Contest (7/10)
2019-2020 ACM-ICPC Brazil Subregional Programming Contest Problem A Artwork (并查集)