#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;constint maxn =100010, maxm = maxn *2;typedeflonglong ll;typedef pair<ll, ll> P;int h[maxn], e[maxm], ne[maxm], idx;int N;
ll wv[maxn], we[maxm];
ll sz[maxn], sum_wv[maxn], d[maxn], A[maxn], B[maxn], W;voidadd(int a,int b,int c){
e[idx]= b, ne[idx]= h[a], we[idx]= c, h[a]= idx++;}//第一个返回值是子树大小,第二个返回值是子树点权之和。
P dfs1(int u,int fa){
P p ={
1, wv[u]};for(int i = h[u]; i !=-1; i = ne[i]){
int v = e[i];if(v == fa)continue;
d[v]= d[u]+ we[i];
P son =dfs1(v, u);
p.first += son.first, p.second += son.second;}
sz[u]= p.first, sum_wv[u]= p.second;return p;}voiddfs2(int u,int fa){
for(int i = h[u]; i !=-1; i = ne[i]){
int v = e[i];if(v == fa)continue;
A[v]= A[u]+(N -2* sz[v])* we[i];
B[v]= B[u]+(W -2* sum_wv[v])* we[i];dfs2(v, u);}}intmain(){
memset(h,-1,sizeof h);scanf("%d",&N);for(int i =1; i <= N; i++){
scanf("%d",&wv[i]);//求所有点权之和。
W += wv[i];}for(int i =1; i < N; i++){
int a, b, c;scanf("%d%d%d",&a,&b,&c);add(a, b, c),add(b, a, c);}dfs1(1,-1);for(int i =1; i <= N; i++){
A[1]+= d[i];
B[1]+= wv[i]* d[i];}dfs2(1,-1);for(int i =1; i <= N; i++){
printf("%lld\n", wv[i]* A[i]+ B[i]);}return0;}
B. Perfect Flush
题意:给出n个数 ∈ [ 1 , k ] \in [ 1 , k ] ∈[1,k],找出它的子序列中,字典序最小的 1~k 的全排列。
用单调栈去解题(单调增大)。
首先统计每个数最后出现的一个位置。然后遍历这个序列,我们称现在遍历到的这个序列的数为 x i x_i xi,做一下操作
如果 x i x_i xi还未出现在答案序列,并且答案序列不为空,就比较 x i x_i xi 和答案序列中最后一个数的大小。如果大于原序列中的最后一个数,直接放到答案序列就行,如果小于,就看后面还是否会出现当前答案序列的最后一个数,如果后面不会再出现了,也直接加到答案序列。
如果 x i x_i xi 已经出现在答案序列,跳过。
#include<cstdio>#include<algorithm>usingnamespace std;constint maxn =200010;int a[maxn], stk[maxn], p[maxn], N, K;//记录当前数字有没有出现在答案里面。bool vis[maxn];intmain(){
scanf("%d%d",&N,&K);for(int i =1; i <= N; i++){
scanf("%d",&a[i]);//记录最后一次出现的位置
p[a[i]]= i;}int top =0;for(int i =1; i <= N; i++){
if(vis[a[i]])continue;while(top && a[i]< stk[top]&& p[stk[top]]> i){
vis[stk[top]]=false;--top;}
stk[++top]= a[i];
vis[a[i]]=true;}for(int i =1; i <= K; i++)printf("%d%c", stk[i], i == K ?'\n':' ');return0;}
E. Rainbow Strings
统计每个字母出现的次数 c n t 1 , c n t 2 , . . . , c n t n cnt_1, cnt_2, ... , cnt_n cnt1,cnt2,...,cntn. 然后答案就是 c n t 1 ∗ c n t 2 ∗ . . . ∗ c n t n cnt_1*cnt_2*...*cnt_n cnt1∗cnt2∗...∗cntn.
#include<iostream>#include<algorithm>usingnamespace std;constint maxn =2010;int field[maxn][maxn];int N, M;int dx[]={
0,0,1,-1}, dy[]={
1,-1,0,0};voiddfs(int x,int y){
field[x][y]=1;for(int i =0; i <4; i++){
int nx = x + dx[i], ny = y + dy[i];if(nx <0|| nx > N +1|| ny <0|| ny > M +1|| field[nx][ny])continue;dfs(nx, ny);}}intmain(){
scanf("%d%d",&N,&M);char c;for(int i =1; i <= N; i++){
for(int j =1; j <= M; j++){
cin >> c;if(c =='\\') field[2* i -1][2* j -1]= field[2* i][2* j]=1;elseif(c =='/') field[2* i -1][2* j]= field[2* i][2* j -1]=1;}}
N *=2, M *=2;int ans =0;for(int i =1; i <= N; i++){
for(int j =1; j <= M; j++){
if(field[i][j]==0)dfs(i, j), ans++;}}
cout << ans -1<< endl;return0;}