2018-2019 ACM-ICPC Brazil Subregional Programming Contest
2018-2019 ACM-ICPC Brazil Subregional Programming Contest
C. Pizza Cutter
-
题意:一个矩形,给你一些横向纵向的边,问你能把矩形划分成多少区域?
-
题解:打表找规律,答案为点数加边数+1,横纵交点能直接得到,同向交点即为两个方向的逆序对数量
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int x,y; int h,v; ll c[N]; PII a[N],b[N]; vector<int> alla,allb; ll ans; int get_alla(int x){ return lower_bound(alla.begin(),alla.end(),x)-alla.begin()+1; } int get_allb(int x){ return lower_bound(allb.begin(),allb.end(),x)-allb.begin()+1; } ll lowbit(ll x){ return x&(-x); } void update(int n,int i,int k){ while(i<=n){ c[i]+=k; i+=lowbit(i); } } ll query(int i){ ll res=0; while(i){ res+=c[i]; i-=lowbit(i); } return res; } int main() { scanf("%d %d",&x,&y); scanf("%d %d",&h,&v); for(int i=1;i<=h;++i){ scanf("%d %d",&a[i].fi,&a[i].se); alla.pb(a[i].se); } for(int i=1;i<=v;++i){ scanf("%d %d",&b[i].fi,&b[i].se); allb.pb(b[i].se); } sort(a+1,a+1+h); sort(b+1,b+1+v); sort(alla.begin(),alla.end()); sort(allb.begin(),allb.end()); alla.erase(unique(alla.begin(),alla.end()),alla.end()); allb.erase(unique(allb.begin(),allb.end()),allb.end()); ans+=h+v+1ll*h*v; for(int i=1;i<=h;++i){ int cur=get_alla(a[i].se); ans+=i-1-query(cur); update((int)alla.size(),cur,1); } me(c,0,sizeof(c)); for(int i=1;i<=v;++i){ int cur=get_allb(b[i].se); ans+=i-1-query(cur); update((int)allb.size(),cur,1); } printf("%lld\n",ans+1); return 0; }
D. Unraveling Monty Hall
签到
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n;
int x;
int main() {
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;++i){
scanf("%d",&x);
if(x!=1) ans++;
}
printf("%d\n",ans);
return 0;
}
E. Enigma
签到
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
char t[N],s[N];
int main() {
scanf("%s",t+1);
scanf("%s",s);
int n=strlen(t+1),m=strlen(s);
int ans=0;
for(int i=1;i+m-1<=n;++i){
bool flag=true;
for(int j=0;j<m;++j){
if(t[i+j]==s[j]){
flag=false;
break;
}
}
if(flag) ans++;
}
printf("%d\n",ans);
return 0;
}
F. Music Festival
-
题意:有\(n\)个舞台,每个舞台都有不同的时间端进行表演,每个表演都有权值,你每个舞台都至少要观看一场演出,每个演出的时间段都不能相交,问你观看演出的最大权值为多少,如果不能每个舞台都观看则输出-1
-
题解:\(n\)最大只有\(10\),考虑状压dp,暴力枚举时间,\(dp[i][j]\)表示当前时间为\(i\),状态为\(j\)的最大权值,再枚举以当前时间为起点的演出,则:\(dp[r][j]=max(dp[r][j],dp[i][k]+w)\),\(r\)表示结束时间,\(j\)表示转移到的状态,\(k\)表示转移前的状态。
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n; struct Node{ int r; int w; int id; }e; vector<Node> v[N]; int dp[90000][1200]; int main() { scanf("%d",&n); me(dp,-1,sizeof(dp)); for(int i=1;i<=n;++i){ int m; scanf("%d",&m); for(int j=1;j<=m;++j){ int l,r,w; scanf("%d %d %d",&l,&r,&w); v[l].pb({r,w,i}); } } for(int i=1;i<=86400;++i){ dp[i][0]=0; for(int j=1;j<(1<<n);++j){ dp[i][j]=max(dp[i][j],dp[i-1][j]); } for(int j=0;j<(int)v[i].size();++j){ for(int k=0;k<(1<<n);++k){ if(dp[i][k]==-1) continue; int now=k|(1<<(v[i][j].id-1)); dp[v[i][j].r][now]=max(dp[v[i][j].r][now],dp[i][k]+v[i][j].w); } } } printf("%d\n",dp[86400][(1<<n)-1]); return 0; }
I. Switches
不难发现\(2n\)次后就复原了,所以枚举两次\(n\)模拟就好了。
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int n,m;
vector<int> v[N];
unordered_map<int,int> mp;
int main() {
scanf("%d %d",&n,&m);
int l;
scanf("%d",&l);
for(int i=1;i<=l;++i){
int x;
scanf("%d",&x);
mp[x]=1;
}
for(int i=1;i<=n;++i){
int k;
scanf("%d",&k);
for(int j=1;j<=k;++j){
int x;
scanf("%d",&x);
v[i].pb(x);
}
}
for(int i=1;i<=n;++i){
for(auto w:v[i]){
mp[w]=1-mp[w];
}
bool flag=true;
for(int j=1;j<=m;++j){
if(mp[j]==1){
flag=false;
break;
}
}
if(flag){
printf("%d\n",i);
return 0;
}
}
for(int i=1;i<=n;++i){
for(auto w:v[i]){
mp[w]=1-mp[w];
}
bool flag=true;
for(int j=1;j<=m;++j){
if(mp[j]==1){
flag=false;
break;
}
}
if(flag){
printf("%d\n",n+i);
return 0;
}
}
puts("-1");
return 0;
}
L. Subway Lines
-
题意:一颗\(n\)个结点的树,\(q\)个询问,每次给你\(4\)个点,代表两条路径,问你两条路径的交点数
-
题解:树上边的问题,不难想到树链剖分,分别对两条路径更新,在线段树将路径上的点+1,然后再查询任意一条路径,路径上权值为2的点即为两条路径相交的点
-
代码:
#include <bits/stdc++.h> using namespace std; const int N=1e6+10; #define ll long long #define pb push_back int n,q; int dep[N],f[N],son[N],sz[N],wt[N],top[N],id[N],cnt; vector<int> edge[N]; struct Node{ int l,r; int cnt,tag,sum; int f; }tr[N<<4]; void push_up(int u){ tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void push_down(int u){ if(tr[u].f){ tr[u<<1].cnt=tr[u<<1].tag=tr[u<<1].sum=0; tr[u<<1|1].cnt=tr[u<<1|1].tag=tr[u<<1|1].sum=0; tr[u<<1].f=tr[u<<1|1].f=1; tr[u].f=0; } if(tr[u].tag){ tr[u<<1].cnt+=tr[u].tag; if(tr[u<<1].cnt==2) tr[u<<1].sum=tr[u<<1].r-tr[u<<1].l+1; tr[u<<1].tag+=tr[u].tag; tr[u<<1|1].cnt+=tr[u].tag; if(tr[u<<1|1].cnt==2) tr[u<<1|1].sum=tr[u<<1|1].r-tr[u<<1|1].l+1; tr[u<<1|1].tag+=tr[u].tag; tr[u].tag=0; } } void build(int u,int l,int r){ if(l==r){ tr[u]={l,r,0,0,0,0}; return; } tr[u]={l,r,0,0,0,0}; int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); push_up(u); } void update(int u,int L,int R,int f){ if(tr[u].l>=L && tr[u].r<=R){ if(f){ tr[u].cnt=tr[u].sum=0; tr[u].f=1; return; } tr[u].cnt++; tr[u].tag++; if(tr[u].cnt==2) tr[u].sum=(tr[u].r-tr[u].l+1); return; } push_down(u); int mid=(tr[u].l+tr[u].r)>>1; if(L<=mid) update(u<<1,L,R,f); if(R>mid) update(u<<1|1,L,R,f); push_up(u); } int query(int u,int L,int R){ if(tr[u].l>=L && tr[u].r<=R) return tr[u].sum; push_down(u); int mid=(tr[u].l+tr[u].r)>>1; int res=0; if(L<=mid) res+=query(u<<1,L,R); if(R>mid) res+=query(u<<1|1,L,R); return res; } void dfs1(int u,int fa,int deep){ dep[u]=deep; f[u]=fa; sz[u]=1; int mxson=-1; for(auto to:edge[u]){ if(to==fa) continue; dfs1(to,u,deep+1); sz[u]+=sz[to]; if(sz[to]>mxson) son[u]=to,mxson=sz[to]; } } void dfs2(int u,int topf){ id[u]=++cnt; wt[cnt]=1; top[u]=topf; if(!son[u]) return; dfs2(son[u],topf); for(auto to:edge[u]){ if(to==f[u] || to==son[u]) continue; dfs2(to,to); } } void updrange(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); update(1,id[top[x]],id[x],0); x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); update(1,id[x],id[y],0); } int queryrange(int x,int y){ int ans=0; int res=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); res=query(1,id[top[x]],id[x]); ans+=res; x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); res=query(1,id[x],id[y]); ans+=res; return ans; } int main(){ scanf("%d %d",&n,&q); for(int i=1;i<n;++i){ int u,v; scanf("%d %d",&u,&v); edge[u].pb(v); edge[v].pb(u); } dfs1(1,0,1); dfs2(1,1); build(1,1,n); while(q--){ int a,b,c,d; scanf("%d %d %d %d",&a,&b,&c,&d); updrange(a,b); updrange(c,d); printf("%d\n",queryrange(a,b)); update(1,1,n,1); } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮