文章目录
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
N−ans/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
4∗4=6。
给你一个
m
m
m,让你计算出
n
n
n使得
n
∗
n
=
m
n*n=m
n∗n=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+1−i]因此,
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;
}