2019-2020 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)


2019-2020 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)

A ( √ ) (√) ()
B ( √ ) (√) ()
C ( √ ) (√) ()
D ( √ ) (√) ()
E ( √ ) (√) ()
F
G
H
I ( √ ) (√) ()
J
K
L ( √ ) (√) ()
M ( √ ) (√) ()

A.Radio Prize

题意:
给你一颗树,每个节点都有一个点权值,两点之间还有一定的距离让你求出每个节点到其他所有节点的点权值之和乘以两点的距离 之和;
题解:在这里插入图片描述

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
ll t[111111],siz[111111],qz[111111],sum[111111],sumq[111111],ans[111111];
vector< pair<int,ll> >v[111111];
int n,x,y,z;
ll num=0;
void dfs(int fa,int u){
	for(int i=0;i<v[u].size();i++){
		int x=v[u][i].first;
		ll y=v[u][i].second;
		if(x!=fa){
			dfs(u,x);
			siz[u]+=siz[x];
			qz[u]+=qz[x];
			sum[u]+=y*siz[x]+sum[x];
			sumq[u]+=y*qz[x]+sumq[x];
		}
	}
	siz[u]++;
	qz[u]+=t[u];
	return;
}
void dfs2(int fa,int u){
	ans[u]=t[u]*sum[u]+sumq[u];
	for(int i=0;i<v[u].size();i++){
		int x=v[u][i].first;
		ll y=v[u][i].second;
		if(x!=fa){
			sum[x]=sum[u]+y*(n-siz[x])-y*siz[x];
			sumq[x]=sumq[u]+y*(num-qz[x])-y*qz[x];
			dfs2(u,x);
		}
	}
	return;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>t[i],num+=t[i];
	for(int i=1;i<n;i++){
		cin>>x>>y>>z;
		v[x].push_back(make_pair(y,z));
		v[y].push_back(make_pair(x,z));
	}
	dfs(0,1);
	dfs2(0,1);
	for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
    return 0;
}

B.Perfect Flush

题意:
给出 n n n个数 ∈ [ 1 , k ] ∈ [ 1 , k ] [1,k],找出它的子序列中,字典序最小的排序。
解析:
预处理每个数字最后出现的位置。然后用栈维护答案。如果栈里已经有当前的数字,那么跳过。如果没有,把前面的小于这个数字且最后出现的位置大于当前位置的数字删掉,插入当前数字。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int last[222222];
int a[222222];
int f[222222];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	stack<int>st;
	memset(f,0,sizeof f);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		last[a[i]]=i;
	}
	for(int i=1;i<=n;i++){
		if(f[a[i]]==0){
			f[a[i]]=1;
			int v;
			while(!st.empty()){
				v=st.top();
				if(last[v]>i&&a[i]<v){
					f[v]=0;
					st.pop();
				}
				else break;
			}
			st.push(a[i]);
		}
	}
	int k=0;
	while(!st.empty()){
		int v=st.top();
		a[++k]=v;
		st.pop();
	}
	for(int i=k;i>=1;i--){
		cout<<a[i]<<" ";
	}
    return 0;
}

C.Coloring Contention

题意:
相邻的两个点颜色不同。
求从1点走到n点,需要转换颜色的最小次数。
题解:
显然答案为最短路-1。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int dis[211111];
int head[211111];
struct node{
	int u,v,nex,w;
}edge[211111];
void dij(int x){
	dis[x]=0;
	priority_queue<pair<int,int> >q;
	q.push(make_pair(-dis[x],x));
	while(!q.empty()){
		int now=q.top().second;q.pop();
		for(int i=head[now];i!=-1;i=edge[i].nex){
			int v=edge[i].v;
			int d=edge[i].w;
			if(dis[v]>dis[now]+d){
				dis[v]=dis[now]+d;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n,m,x,y;
	int cnt=0;
	memset(head,-1,sizeof head);
	memset(dis,inf,sizeof dis);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		edge[cnt]=node{x,y,head[x],1};
		head[x]=cnt++;
		edge[cnt]=node{y,x,head[y],1};
		head[y]=cnt++;
	}
	dij(1);
	cout<<dis[n]-1;
    return 0;
}

D.Dividing By Two

题意:
有两种操作:
1. B + 1 B+1 B+1
2. B / 2 B/2 B/2前提是B为偶数。
求把 B B B变成 A A A的最小次数。
题解:
签到题。能除2就除2。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 1000000009
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int a,b;
	int ans=0;
	cin>>a>>b;
	while(a>b){
		if(a%2){
			a++;
		}
		else a/=2;
		ans++;
	}
	ans+=(b-a);
	cout<<ans;
    return 0;
}

E.Rainbow Strings

题意:
给你一串字符串,题目保证为小写字母。
问,能组成多少种每个字符都不一样的字符串。可以为空。
题解:
对于每一种字母来说,他的选择有 C n 1 + 1 ( 不 选 ) = n + 1 C_n^1+1(不选)=n+1 Cn1+1=n+1种。
所以总的答案就为 ∏ i = a z \prod_{i=a}^z i=az n i + 1 n_i+1 ni+1;

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 11092019
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
ll a[30];
char ch[111111];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>ch;
	memset(a,0,sizeof a);
	int len=strlen(ch);
	for(int i=0;i<len;i++){
		a[ch[i]-'a']++;
	}
	ll ans=1;
	for(int i=0;i<26;i++){
		ans=ans*(a[i]+1)%mod;
	}
	cout<<ans%mod;
    return 0;
}

I.Error Correction

题意:
给你 N 个长度相同的字符串,问你最多选多少个可以使他们两两之间不能通过交换一对字符串而相等,
题解:
二分图匹配。对于能交换两个字符使他们相等的字符串,我们连一条边。用二分图匹配计算下能匹配上的数量 a n s ans ans。那么我们只需要去掉 a n s / 2 ans/2 ans/2就可以使两两直接不匹配。
答案就为: N − a n s / 2 N-ans/2 Nans/2

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int g[1505],n,t,m,k,x,num;;
int a[1505][1505],b[1505],tim[1505],lc[1505][18];
bool find(int x){
	for(int j=1;j<=n;j++){
		if(a[x][j]==1&&b[j]==0){
			b[j]=1;
			if(find(g[j])||g[j]==0){
				g[j]=x;
				return 1;
			}
		}
	}
	return 0;
}
string s[1111];
int main(){
	int y,xx,yy;
		cin>>n;
		memset(a,0,sizeof a);
		for(int i=1;i<=n;i++){
			cin>>s[i];
		}
		int len=s[1].length();
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				int num=0;
				for(int k=0;k<len;k++){
					if(s[i][k]!=s[j][k])num++;
				}
				if(num==2)a[i][j]=1;
			}
		}
		int ans=0;
		memset(g,0,sizeof g);
		for(int i=1;i<=n;i++){
			memset(b,0,sizeof b);
			if(find(i))ans++;
		}
		cout<<n-ans/2;
}

L.Carry Cam Failure

题意:
现在有一种新的乘法,他没有进位。即 4 ∗ 4 = 6 4*4=6 44=6
给你一个 m m m,让你计算出 n n n使得 n ∗ n = m n*n=m nn=m
题解:
因为没有了进位。我们很容易发现 n n n的长度 a l e n alen alen就为 m m m的长度 ( l e n + 1 ) / 2 (len+1)/2 len+1/2
对于 m m m的每一位我们可以发现: m [ x ] = ∑ i = 1 l e n n [ i ] ∗ n [ x + 1 − i ] m[x]=\sum_{i=1}^{len}n[i]*n[x+1-i] m[x]=i=1lenn[i]n[x+1i]因此, m [ x ] m[x] m[x]只和 n n n的前x项有关。
所以我们只需要从前往后暴力枚举 n n n的每一位数字就行了。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 11092019
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
int a[1111];
int s[1111];
char str[1111];
int f=0,len,alen;
void dfs(int x){
	if(f==1)return ;
	if(x==len+1){
		f=1;
		for(int i=1;i<=alen;i++)printf("%d",a[i]);
		return ;
	}
	for(int i=0;i<=9;i++){
		int temp=0;
		a[x]=i;
		if(x>alen&&i!=0)return;
		for(int j=1;j<=x;j++){
			if(x+1-j>alen)continue;
			temp+=a[j]*a[(x+1-j)];
			temp%=10;
		}
		if(temp==s[x])dfs(x+1);
	}
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin>>str;
    len=strlen(str);
    alen=len/2+1;
    for(int i=1;i<=len;i++)s[i]=str[i-1]-'0';
	dfs(1);
	if(f==0)printf("-1");
    return 0;
}

M.Maze Connect

题意:
给你一个地图,最少拆掉多少个障碍物使地图联通。
题解:
搜索一下有多少个联通区域。答案为连通区域减一。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
#define ll long long
#define maxn 100100 
#define mod 11092019
#define eps 1e-10
#define inf 0x3f3f3f3f
template <typename T>
inline void read(T& X) {
	X = 0; int w = 0; char ch = 0;
	while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
	if (w) X = -X;
}
char s[1111][1111];
int ss[2222][2222];
int vis[2222][2222];
int n,m;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
void dfs(int x,int y){
	vis[x][y]=1;
	for(int i=0;i<4;i++){
		int xx=x+dx[i],yy=y+dy[i];
		if(xx>=0&&yy>=0&&xx<=2*n+3&&yy<=2*m+3&&ss[xx][yy]==0&&vis[xx][yy]==0)dfs(xx,yy);
	}
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin>>n>>m;
    memset(ss,0,sizeof ss);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		cin>>s[i][j];
    		if(s[i][j]=='/'){
    			ss[i*2][j*2+1]=1;
    			ss[i*2+1][j*2]=1;
			}
			else if(s[i][j]=='\\'){
				ss[i*2][j*2]=1;
				ss[i*2+1][j*2+1]=1;
			}
		}
	}
	int ans=0;
	for(int i=0;i<=2*n+3;i++){
		for(int j=0;j<=2*m+3;j++){
			if(vis[i][j]==0&&ss[i][j]==0){
				ans++;
				dfs(i,j);
			}
		}
	}
	cout<<ans-1;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值