2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)

題目鏈接:https://codeforces.com/contest/1252

 

A - Copying Homework

水題

#include<bits/stdc++.h>
using namespace std;
const int mx = 1e5+5;
struct node{
	int id,x;
	bool operator<(const node &a)const{
		return x>a.x;
	}
}a[mx];
int ans[mx];
int main(){
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)	
		scanf("%d",&a[i].x),a[i].id = i;
	sort(a+1,a+n+1);
	for(int i = 1; i <= n; i++)
		ans[a[i].id] = i;
	for(int i = 1; i <= n; i++)
		printf("%d%c",ans[i],i==n?'\n':' ');
	return 0;
}

B - Cleaning Robots

樹形DP

0:以u節點爲根節點的樹,並且u最後不能是鏈的端點的個數

1:u的子樹且u不是鏈的端點的個數

2:u可以做鏈的端點,後面也可以改變不做鏈端點的方案數

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int mx = 1e5 + 10;
int n,m; 
ll dp[mx][3];
vector <int> g[mx];
void dfs_dp(int u,int f) {
	ll pre_1 = 1;
	ll all_cnt = 1;
	for (int i=0;i<g[u].size();i++) {
		int v = g[u][i];
		if (v == f) continue;
		dfs_dp(v,u);
		dp[u][1] = dp[u][1] * (dp[v][1] + dp[v][2]) % mod; // u不是端點 
		dp[u][1] = (dp[u][1] + (dp[v][0] + dp[v][2]) * (dp[u][0] + dp[u][2])) % mod;
		
		// 是端點但要和其他點連接不讓u是鏈的端點
		dp[u][0] = dp[u][0] * (dp[v][1] + dp[v][2]) % mod; //不做連接點 
		dp[u][0] = (dp[u][0] + dp[u][2] * dp[v][2]) % mod;
		ll mul = (all_cnt - pre_1 + mod) % mod;
		dp[u][0] = (dp[u][0] + (dp[v][0] + dp[v][2])*mul) % mod;
		// 是端點,但後面u可以作爲端點也可以不做
		dp[u][2] = (dp[u][2] * dp[v][1] + (dp[v][0] + dp[v][2]) * pre_1) %mod;
	
		pre_1 = pre_1 * dp[v][1] % mod;
		all_cnt = all_cnt * (dp[v][1] + dp[v][2]) %mod;
	}
	dp[u][2] = (dp[u][2] + pre_1) % mod;
}
int main(){
	scanf("%d",&n);
	int u1,v1;
	for (int i=1;i<n;i++){
		scanf("%d%d",&u1,&v1);
		g[u1].push_back(v1);
		g[v1].push_back(u1);
	}
	dfs_dp(1,0);
	ll ans = dp[1][1] + dp[1][2];
	printf("%lld\n",ans%mod);
    return 0;
}

C - Even Path

從行上來看和0/1表示奇偶來看,行要麼是一樣的要麼是互斥的。要想連通一定是在連續的一樣的行中。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
 
int n, m;
int R[maxn], C[maxn];
int lr[maxn], rr[maxn];
int lc[maxn], rc[maxn];
 
void solve() {
	for(int i=2; i<=n; i++) {
		lr[i] = (R[i]%2 == R[i-1]%2) ? lr[i-1] : i;
		lc[i] = (C[i]%2 == C[i-1]%2) ? lc[i-1] : i;
	}
	for(int i=n-1; i>=1; i--) {
		rr[i] = (R[i]%2 == R[i+1]%2) ? rr[i+1] : i;
		rc[i] = (C[i]%2 == C[i+1]%2) ? rc[i+1] : i;
	}
}
 
bool ok(int x1, int y1, int x2, int y2) {
	if((R[x1]+C[y1]) %2 == 1)	return false;
	if((R[x2]+C[y2]) %2 == 1)	return false;
	if(x2<lr[x1] || rr[x1]<x2)	return false;
	if(y2<lc[y1] || rc[y1]<y2)	return false;
	return true;
}
 
int main() {
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++) {
		scanf("%d", &R[i]);
		lr[i] = rr[i] = i;
	}
	for(int i=1; i<=n; i++) {
		scanf("%d", &C[i]);
		lc[i] = rc[i] = i;
	}
	solve();
	while(m--) {
		int x1, y1, x2, y2;
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		if(ok(x1, y1, x2, y2))	printf("YES\n");
		else	printf("NO\n");
	}
}

D.Find String in a Grid

待做

E - Songwriter

從後往前推每個位置的可以有解的取值範圍,然後最後在從前往後去最小

#include <bits/stdc++.h>
using namespace std;
const int mx = 1e5 + 10;
int n,L,R,K;
int a[mx];
int up[mx],down[mx];
int main() {
	scanf("%d%d%d%d",&n,&L,&R,&K);
	for (int i=1;i<=n;i++) {
		scanf("%d",a+i);
	}
	up[n] = R, down[n] = L;
	for (int i=n-1;i>=1;i--) {
		if (a[i]==a[i+1]) 
			up[i] = up[i+1],down[i] = down[i+1];
		else if (a[i] > a[i+1]) {
			up[i] = min(R,up[i+1]+K);
			down[i] = down[i+1] + 1;
		} else {
			up[i] = up[i+1] - 1;
			down[i] = max(L,down[i+1]-K);
		}
		if (up[i] < L || down[i] > R || down[i] > up[i])
			return 0*puts("-1");
	}
	int now = down[1];
	printf("%d ",now);
	for (int i=2;i<=n;i++) {
		if (a[i] > a[i-1]) {
			now = max(down[i],now+1);
		} else if (a[i] < a[i-1]){
			now = max(down[i],now-K);
		}
		printf("%d ",now);
	}
	return 0;
}

F - Regular Forestation

Hash+求重心,主要注意的是一個樹最多有兩個重心

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mx = 4e3 + 10;
const ull base = 1e4 + 7;
 
int n;
vector <int> g[mx],root;
int siz[mx],son[mx];
int msiz,first_rt;
void dfs_siz(int u,int f) {
	siz[u] = 1;
	
	for (int v:g[u]) {
		if (v == f) continue;
		dfs_siz(v,u);
		siz[u] += siz[v];
	}
}
void get_root(int u,int f,int tot) {
	int fsiz = tot - siz[u];
	for (int v: g[u]) if (f != v) {
		fsiz = max(fsiz,siz[v]);
		get_root(v,u,tot);
	}
	if (msiz > fsiz) {
		root.clear();
		root.push_back(u);
		msiz = fsiz;
	} else if (msiz == fsiz)
		root.push_back(u);
}
ull dfs_hash(int u,int f,int d) {
	ull ans = 0;
	for (int v:g[u]) {
		if (v == f || v == first_rt) continue;
		ans += dfs_hash(v,u,d+1);
	}
	return ans * base + d;
}
bool check(ull hash_val) {
	for (int tr : root) {
		if (hash_val == dfs_hash(tr,0,1))
			return 1;
	}
	return 0;
}
int main() {
	scanf("%d",&n);
	int u,v;
	for (int i=1;i<n;i++) {
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	first_rt = -1;
	msiz = 1e7;
	dfs_siz(1,0);
	get_root(1,0,siz[1]);
	first_rt = root[0];
	
	int ans = 0;
	ull hash_val;
	bool ok = 0;
	for (int i : g[first_rt]){
		msiz = 1e7;
		root.clear();
		dfs_siz(i,first_rt);
		get_root(i,first_rt,siz[i]);
		
		if (!ok) {
			hash_val = dfs_hash(root[0],0,1);
			ok = 1;
		}
		else if (!check(hash_val)) return 0*puts("-1");
		ans++;
	}
	printf("%d\n",ans);
	return 0;
}

G - Performance Review

只需要考慮比第一個數大還是小,如果是大的話,第一個人的名次肯定越來越小,一個值比第一個人大,肯定會影響整個後綴,所以就是後綴區間更新維護一下區間最值就好了

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mid (l+r>>1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mx = 1e5 + 10;
int a[mx];
vector <int> g[mx];
int n,m,q,self_val,rk;
int Min[mx<<2],lazy[mx<<2];
void build(int l,int r,int rt) {
	if (l == r) {
		Min[rt] = rk - (int)g[l].size() - 1;
		return ;
	}
	build(lson);
	build(rson);
	Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
}
void push_up(int rt) {
	if (lazy[rt]) {
		Min[rt<<1] += lazy[rt];
		Min[rt<<1|1] += lazy[rt];
		lazy[rt<<1] += lazy[rt];
		lazy[rt<<1|1] += lazy[rt];
		lazy[rt] = 0;
	}
}
void update(int l,int r,int rt,int M,int v) {
	if (M > r) return ;
	if (M <= l) {
		Min[rt] += v;
		lazy[rt] += v;
		return ;
	}
	push_up(rt);
	if (M <= mid) update(lson,M,v);
	update(rson,M,v);
	Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
}
int main() {
	scanf("%d%d%d",&n,&m,&q);
	scanf("%d",&self_val);
	rk = n;
	for (int i=2;i<=n;i++) {
		scanf("%d",a+i);
		if (a[i] > self_val) rk--;
	}
	for (int i=1;i<=m;i++) {
		int c,u;
		scanf("%d",&c);
		for (int j=0;j<c;j++) {
			scanf("%d",&u);
			g[i].push_back(u);
		}
	}
	build(1,m,1);
	for (int i=1;i<m;i++) {
		for (int j : g[i]) if (j > self_val)
			update(1,m,1,i+1,-1);
	}
	int c,id,v;
	while (q--) {
		scanf("%d%d%d",&c,&id,&v);id--;
		if (g[c][id] > self_val && v < self_val)
			update(1,m,1,c+1,1);
		if (g[c][id] < self_val && v > self_val)
			update(1,m,1,c+1,-1);
		g[c][id] = v;
		puts(Min[1]>=0?"1":"0");
	}
	return 0;
}

H - Twin Buildings

排個序,枚舉長度最小值的情況去貪心寬的最大值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5+5;
set<ll>st;
struct point{
	ll x,y;
	bool operator<(const point &a)const{
		return x>a.x;
	}
}a[mx]; 
int main(){
	int n;
	scanf("%d",&n);
	ll ans = 0;
	for(int i = 1; i <= n; i++){
		scanf("%lld%lld",&a[i].x,&a[i].y);
		if(a[i].x>a[i].y)
			swap(a[i].x,a[i].y);
		ans = max(a[i].x*a[i].y,ans);
	}
	sort(a+1,a+n+1);
	for(int i = 1; i <= n; i++){
		ll x = a[i].x;
		auto it = st.lower_bound(a[i].y);
		if(it!=st.end())
			ans = max(ans,2*a[i].x*a[i].y);
		else if(it!=st.begin()){
			it--;
			ans = max(ans,2*a[i].x*(*it));
		}
		st.insert(a[i].y);
	}
	if(ans&1)
		printf("%lld.5\n",ans/2);
	else
		printf("%lld.0\n",ans/2);
	return 0;
}

I.Mission Possible

待做

J - Tiling Terrace

隊友做的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 1e15;
const int mx = 1e5+10;
const int N = 105;
ll dp[N][N][N][2];
char str[mx];
vector<int>s;
int n,m,a,b,c;
ll calc(int n,int i,int j,int k){
	if(dp[n][i][j][k]<0)	return -1;
	if(i>m)	return 1ll*c*j+1ll*m*a+b*dp[n][i][j][k];
	ll sum = 1ll*c*j+1ll*i*a;
	ll x = dp[n][i][j][k];
	ll y = min(1ll*(m-i)/2,dp[n][i][j][k]);
	ll ans = max(dp[n][i][j][k]*b+sum,(dp[n][i][j][k]-y)*b+sum+1ll*y*2*a);
	if(y*2+i<m&&y<dp[n][i][j][k])
		ans = max(ans,(dp[n][i][j][k]-y-1)*b+sum+1ll*y*2*a+a);
	return ans;
}
int main(){
	// freopen("in", "r", stdin);
	scanf("%d%d%d%d%d",&n,&m,&a,&b,&c); 
	s.clear();
	for(int i = 0; i < N; i++)
		for(int j = 0; j < N; j++)
			for(int k = 0; k < N; k++)
				dp[i][j][k][0] = dp[i][j][k][1] = -inf;
	dp[0][0][0][0] = 0;
	scanf("%s",str+1);
	s.push_back(0);
	for(int i = 1; i <= n; i++)
		if(str[i]=='#')
			s.push_back(i);
	s.push_back(n+1);
	for(int i = 0; i < s.size()-1; i++){
		int len  = s[i+1]-s[i]-1;
		for(int j = 0; j < N-1; j++)
			for(int k = 0; k < N-1; k++){
				if(dp[i][j][k][0]>=0){
					dp[i+1][j+len%2][k][0] = max(dp[i][j][k][0]+len/2,dp[i+1][j+len%2][k][0]);
					if(len>=1&&str[s[i+1]+1]=='.')
						dp[i+1][j+(len-1)%2][k+1][1] = max(dp[i][j][k][0]+(len-1)/2,dp[i+1][j+(len-1)%2][k+1][1]);
				}
				if(dp[i][j][k][1]>=0){
					if(len>=1)
						dp[i+1][j+(len-1)%2][k][0] = max(dp[i][j][k][1]+(len-1)/2,dp[i+1][j+(len-1)%2][k][0]);
					if(len>=2&&str[s[i+1]+1]=='.')
						dp[i+1][j+len%2][k+1][1] = max(dp[i][j][k][1]+(len-2)/2,dp[i+1][j+len%2][k+1][1]);				
				}
			}
	}
	ll ans = 0;
	int n = s.size()-1;
	for(int i = 0; i < N; i++)
		for(int j = 0; j < N; j++)
			ans = max(ans,calc(n,i,j,0));
	printf("%lld\n",ans);
	return 0;
}

K - Addition Robot

矩陣合併線段樹,異或就是矩陣倒置

#include<bits/stdc++.h>
using namespace std;
#define ls 2*rt
#define rs 2*rt+1
#define lson ls,l,mid
#define rson rs,mid+1,r 
const int mx = 1e5+5;
const int mod = 1e9+7;
typedef long long ll;
char str[mx];
struct mat{
	ll x[2][2];
	friend mat operator*(mat a,mat b){
		mat c;
		for(int i = 0; i < 2; i++)
			for(int j = 0; j < 2; j++){
				c.x[i][j] = 0;
				for(int k = 0; k < 2; k++)
					c.x[i][j] = (c.x[i][j]+a.x[i][k]*b.x[k][j]%mod)%mod;
			}
		return c;
	} 
};
struct node{
	mat a;
	ll lazy;
}sum[mx<<2];
void change(mat &a){
	swap(a.x[0][0],a.x[0][1]);
	swap(a.x[1][0],a.x[1][1]);
	swap(a.x[0][0],a.x[1][0]);
	swap(a.x[0][1],a.x[1][1]); 
}
void push_up(int rt){
	sum[rt].a = sum[ls].a*sum[rs].a;
}
void push_down(int rt){
	if(sum[rt].lazy){
		change(sum[rs].a);
		change(sum[ls].a);
		sum[rs].lazy ^= 1;
		sum[ls].lazy ^= 1;
		sum[rt].lazy = 0;
	}
}
void built(int rt,int l,int r){
	sum[rt].lazy = 0;
	if(l==r){
		if(str[l]=='A'){
			sum[rt].a.x[0][0] = 1;
			sum[rt].a.x[0][1] = 0;
			sum[rt].a.x[1][1] = 1;
			sum[rt].a.x[1][0] = 1;  
		}
		else{
			sum[rt].a.x[0][0] = 1;
			sum[rt].a.x[0][1] = 1;
			sum[rt].a.x[1][0] = 0;
			sum[rt].a.x[1][1] = 1;
		}
		return;
	}
	int mid = (l+r)/2;
	built(lson);
	built(rson);
	push_up(rt);
} 
void update(int rt,int l,int r,int L,int R){
	if(l==L&&R==r){
		change(sum[rt].a);
		sum[rt].lazy ^= 1;
		return;
	}
	int mid = (l+r)/2;
	push_down(rt);
	if(L>mid) update(rson,L,R);
	else if(R<=mid) update(lson,L,R);
	else update(lson,L,mid),update(rson,mid+1,R);
	push_up(rt);
}
mat query(int rt,int l,int r,int L,int R){
	if(l==L&&r==R){
		return sum[rt].a; 
	}	
	int mid = (l+r)/2;
	push_down(rt);
	if(L>mid) return query(rson,L,R);
	else if(R<=mid)	return query(lson,L,R);
	else return query(lson,L,mid)*query(rson,mid+1,R);
}
int main(){
	int n,q;
	scanf("%d%d",&n,&q);
	scanf("%s",str+1);
	built(1,1,n);
	while(q--){
		int op;
		scanf("%d",&op);
		if(op==1){
			int L,R;
			scanf("%d%d",&L,&R);
			update(1,1,n,L,R);
		}
		else{
			int L,R;
			ll a,b;
			scanf("%d%d",&L,&R);
			scanf("%lld%lld",&a,&b);
			mat ans = query(1,1,n,L,R);
			mat x = {a,b,0,0};
			ans = x*ans;
			printf("%lld %lld\n",ans.x[0][0],ans.x[0][1]);
		}
	}
	return 0;
}

L.Road Construction

待做

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章