A - AKIBA

模拟即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N;
string s,tar = "AKIHABARA";
bool Solve() {
cin >> s;
if(s.length() > 9) {
return false;
}
for(int i = 0 ; i < 9 ; ++i) {
if(s.length() <= i) s += "A";
if(s[i] != tar[i]) {
if(tar[i] == 'A') {
s.insert(i,1,'A');
}
else return false;
}
}
if(s != tar) return false;
return true;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
if(Solve()) puts("YES");
else puts("NO");
return 0;
}

B - Palindrome-phobia

题解

abc出现次数的最大值和最小值相差不超过1

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
char s[MAXN];
int cnt[4];
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
scanf("%s",s + 1);
int N = strlen(s + 1);
for(int i = 1 ; i <= N ; ++i) {
cnt[s[i] - 'a']++;
}
int minn = min(min(cnt[0],cnt[1]),cnt[2]);
int mmax = max(max(cnt[0],cnt[1]),cnt[2]);
if(mmax - minn <= 1) puts("YES");
else puts("NO");
return 0;
}

C - Time Gap

题解

显然每个时间有超过三个人答案一定是0

之后对于每个时间里的人进行枚举是d还是24 - d即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int cnt[15];
int N,D[55];
bool vis[25],mark[15],c[25];
void Init() {
read(N);
for(int i = 1 ; i <= N ; ++i) {read(D[i]);cnt[D[i]]++;}
}
void Solve() {
if(cnt[0] || cnt[12] >= 2) {puts("0");return;}
int S = 0;
int ans = 0,d = 12;
for(int i = 1 ; i <= 12 ; ++i) { if(cnt[i] > 2) {puts("0");return;}
if(cnt[i] == 2) {
vis[i] = 1;vis[24 - i] = 1;
}
else if(cnt[i]) {d = min(d,i);S |= 1 << i - 1;mark[i] = 1;}
}
for(int T = S ; ; T = S & (T - 1)) {
memcpy(c,vis,sizeof(vis));
for(int i = 1 ; i <= 12 ; ++i) {
if(mark[i]) {
if(T >> (i - 1) & 1) c[24 - i] = 1;
else c[i] = 1;
}
}
int pre = 0,t = d;
for(int i = 1 ; i <= 24 ; ++i) {
if(c[i]) {t = min(t,i - pre);pre = i;}
}
ans = max(ans,t);
if(T == 0) break;
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

D - Zabuton

题解

如果两个相邻的点\(a\)和\(b\),前面的前缀和是\(x\)

那么我们有

\(min(H[a],H[b] - P[a]) >= x\)

\(min(H[b],H[a] - P[b]) >= x\)

我们希望允许尽量宽松的x

如果\(min(H[a],H[b] - P[a]) < min(H[b],H[a] - P[b])\)的话,a在前,否则b在前

排序后进行\(dp[i][j]\)表示到第\(i\)个点选了\(j\)个点最小前缀和即可,用前缀min优化更新

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 5005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int H[MAXN],P[MAXN],id[MAXN],N;
int64 sum[MAXN];
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) {
read(H[i]);read(P[i]);id[i] = i;
}
sort(id + 1,id + N + 1,[](int a,int b) {
if(H[a] < H[b] - P[a]) return true;
if(H[b] < H[a] - P[b]) return false;
return H[a] + P[a] < H[b] + P[b];
});
for(int i = 1 ; i <= N ; ++i) sum[i] = 1e18;
for(int i = 1 ; i <= N ; ++i) {
int u = id[i];
for(int j = N ; j >= 1 ; --j) {
if(H[u] >= sum[j - 1]) {
sum[j] = min(sum[j],sum[j - 1] + P[u]);
}
}
}
for(int i = N ; i >= 1 ; --i) {
if(sum[i] != 1e18) {out(i);enter;return;}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

E - Combination Lock

题解

处理成差分,对称位置的差分和为0

例如abcba

可以得到的差分是

相当于数列

0123210

111-1-1-1

而有区间加呢,相当于在前面打了一个+1,后面打了一个-1

我们把这两个位置连边

并且给所有对称位置连边

合法的情况仅当一个联通块和为0

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
char s[MAXN];
int a[MAXN],N,M;
struct node {
int to,next;
}E[MAXN * 10];
int head[MAXN],sumE,sum;
bool vis[MAXN];
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void Init() {
scanf("%s",s + 1);
N = strlen(s + 1);
s[0] = 'a';s[N + 1] = 'a';
for(int i = 1 ; i <= N + 1; ++i) a[i] = (s[i] - s[i - 1] + 26) % 26;
read(M);
int L,R;
for(int i = 1 ; i <= M ; ++i) {
read(L);read(R);
add(L,R + 1);add(R + 1,L);
}
for(int i = 1 ; i <= N + 1 ; ++i) {
add(i,N + 2 - i);
}
}
void dfs(int u) {
vis[u] = 1;
sum = (sum + a[u]) % 26;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {
dfs(v);
}
}
}
void Solve() {
bool flag = 1;
for(int i = 1 ; i <= N + 1 ; ++i) {
if(!vis[i]) {
sum = 0;
dfs(i);
if(sum != 0) {flag = 0;break;}
}
}
if(flag) puts("YES");
else puts("NO");
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

F - Distribute Numbers

题解

给第一行填上1 - K,很容易发现N的下界是\(K(K - 1) + 1\)

然后给第2到\(K\)行全填上1,\(K + 1\)到\(2K\)全填上2,以此类推

然后我们再把剩余未分配的数全填到\(2\)行到\(K\)行大小为\(K - 1\)的正方形矩阵里

然后我们要把这个正方形矩阵划分成\(K - 1\)种,每种\(K - 1\)条不相交的链

把\(K - 1\)选一个质数可以完成这个操作

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 5005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
vector<int> v[1500];
int N = 1407;
int K = 38;
int a[45][45];
void Solve() {
for(int i = 1 ; i <= K ; ++i) v[1].pb(i);
int t = 0;
for(int i = 2 ; i <= N ; i += (K - 1)) {
++t;
for(int j = i ; j <= i + (K - 1) - 1 ; ++j) v[j].pb(t);
}
t = K;
for(int i = 0 ; i < K - 1 ; ++i) {
for(int j = 0 ; j < K - 1 ; ++j) {
a[i][j] = ++t;
v[i + 2].pb(t);
}
}
t = 0;
for(int i = K + 1 ; i <= N ; i += (K - 1)) {
for(int j = 0 ; j < K - 1 ; ++j) {
int p = j;
for(int h = 0 ; h < K - 1 ; ++h) {
v[i + j].pb(a[h][p]);
p = (p + t) % (K - 1);
}
}
++t;
}
out(N);space;out(K);enter;
for(int i = 1 ; i <= N ; ++i) {
for(auto b : v[i]) {
out(b);space;
}
enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

G - Mancala

题解

很容易想到\(sum[i][j]\)表示第\(i\)个点还需要后面给加\(j\)次的价值总和,\(cnt[i][j]\)表示第\(i\)个点还需要后面给加\(j\)次的方案数

由于能用到的状态不多,可以记忆化搜索,答案是\(dp[N][0]\)

转移就枚举这第\(i\)位放了\(p\)个,需要后面加\(d\)个

简单列个方程可以知道后面需要加\(d + \lfloor \frac{d + p}{i} \rfloor\)

然后加上\(cnt[i - 1][d + \lfloor \frac{d + p}{i} \rfloor] * (p - \frac{d + p}{i})\)

边界是对于1,\(sum[1][d] = \frac{(K - 1) * (K + 2)}{2} - 2 * d,cnt[1][d] = K + 1\)

因为1如果不满的话加多少都会扔掉

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 1000000007;
bool vis[105][100005];
int sum[105][100005],cnt[105][100005];
int N,K;
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void update(int &x,int y) {
x = inc(x,y);
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
void dfs(int p,int d) {
if(vis[p][d]) return;
vis[p][d] = 1;
if(p == 1) {
cnt[p][d] = K + 1;sum[p][d] = (mul(2,MOD - d) + (K + 2) * (K - 1) / 2) % MOD;
return ;
}
for(int i = 0 ; i < p ; ++i) {
if(i > K) break;
dfs(p - 1,d + (d + i) / p);
update(cnt[p][d],cnt[p - 1][d + (d + i) / p]);
update(sum[p][d],inc(sum[p - 1][d + (d + i) / p] ,mul(cnt[p - 1][d + (d + i) / p] ,inc(i, MOD - (d + i) / p))));
}
if(p <= K) {
dfs(p - 1,d + 1 + d / p);
update(cnt[p][d],cnt[p - 1][d + 1 + d / p]);
update(sum[p][d],inc(sum[p - 1][d + 1 + d / p], mul(cnt[p - 1][d + 1 + d / p],inc(p, MOD - d / p - 1))));
}
for(int i = p + 1 ; i <= K ; ++i) {
dfs(p - 1,d);
update(cnt[p][d],cnt[p - 1][d]);
update(sum[p][d],inc(sum[p - 1][d],mul(cnt[p - 1][d], i)));
}
}
void Solve() {
read(N);read(K);
dfs(N,0);
out(sum[N][0]);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

H - Poor Penguin

题解

题解里的图画的挺好的

就是我们考虑把大矩形分成小矩形的代价是什么

例如一个矩形\([lx,ly,rx,ry]\)

我把它从\([lx,ly,i,j]\)里分出来

需要就是把

\([lx,ry + 1,rx,j]\)和\([rx + 1,ly,i,ry]\)里所有的障碍都扣去

然后我们对于每个包含p点的矩形,计算使得从P开始左上右上左下右下的一个角都扣去的最小代价

其实这是\(n^6\)的,怂的一批,不过记忆化搜索加上一点剪枝和AtCoder强大的评测机,好像还是不到1s的样子

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
bool vis[45][45][45][45];
int dp[45][45][45][45];
char s[45][45];
int H,W,sum[45][45];
void Init() {
read(H);read(W);
for(int i = 1 ; i <= H ; ++i) scanf("%s",s[i] + 1);
}
int query(int lx,int ly,int rx,int ry) {
return sum[rx][ry] + sum[lx - 1][ly - 1] - sum[rx][ly - 1] - sum[lx - 1][ry];
}
int dfs(int lx,int ly,int rx,int ry) {
if(lx == 1 && ly == 1 && rx == H && ry == W) return 0;
if(vis[lx][ly][rx][ry]) return dp[lx][ly][rx][ry];
int res = 100000;
for(int i = rx + 1 ; i <= H ; ++i) {
for(int j = ry + 1 ; j <= W ; ++j) {
int t = query(lx,ry + 1,rx,j) + query(rx + 1,ly,i,ry);
if(t >= res) break;
res = min(t + dfs(lx,ly,i,j),res);
}
}
for(int i = rx + 1 ; i <= H ; ++i) {
for(int j = ly - 1 ; j >= 1 ; --j) {
int t = query(lx,j,rx,ly - 1) + query(rx + 1,ly,i,ry);
if(t >= res) break;
res = min(t + dfs(lx,j,i,ry),res);
}
}
for(int i = lx - 1 ; i >= 1 ; --i) {
for(int j = ly - 1 ; j >= 1 ; --j) {
int t = query(i,ly,lx - 1,ry) + query(lx,j,rx,ly - 1);
if(t >= res) break;
res = min(t + dfs(i,j,rx,ry),res);
}
}
for(int i = lx - 1 ; i >= 1 ; --i) {
for(int j = ry + 1 ; j <= W ; ++j) {
int t = query(i,ly,lx - 1,ry) + query(lx,ry + 1,rx,j);
if(t >= res) break;
res = min(t + dfs(i,ly,rx,j),res);
}
}
vis[lx][ly][rx][ry] = 1;
return dp[lx][ly][rx][ry] = res;
}
void Solve() {
pii p;
for(int i = 1 ; i <= H ; ++i) {
for(int j = 1 ; j <= W ; ++j) {
if(s[i][j] == 'P') p = mp(i,j);
if(s[i][j] == '#') sum[i][j]++;
sum[i][j] = sum[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
}
int ans = 100000;
for(int i = 1 ; i <= H ; ++i) {
for(int j = 1 ; j <= W ; ++j) {
for(int k = i ; k <= H ; ++k) {
for(int h = j ; h <= W ; ++h) {
if(p.fi >= i && p.fi <= k && p.se >= j && p.se <= h) {
int t = query(i,j,p.fi,p.se);
t = min(t,query(p.fi,p.se,k,h));
t = min(t,query(i,p.se,p.fi,h));
t = min(t,query(p.fi,j,k,p.se));
if(t >= ans) continue;
ans = min(t + dfs(i,j,k,h),ans);
}
}
}
}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

I - Full Tournament

题解

观察一下可得

\(a_{i} < a_{i | 2^{k}}\)

我们把这个当做一条边,会连出一个dag,相当于给出拓扑序的一部分回复全部

可以对每个点求一个放的位置取值范围,如果这个点固定了就把左右端点都设成那个值

然后每次选一个右端点最小的放进去,不存在或右端点不合法就是无解了

恢复成原来的观察一下就是二进制反转

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int A[(1 << 18) + 5],N;
vector<int> e[2][(1 << 18) + 5];
int d[2][(1 << 18) + 5];
int L[(1 << 18) + 5],R[(1 << 18) + 5];
int que[2][(1 << 18) + 5],ql,qr,ans[(1 << 18) + 5];
vector<int> st[(1 << 18) + 5],ed[(1 << 18) + 5];
struct cmp {
bool operator () (const int &a,const int &b) const {
return R[a] < R[b] || (R[a] == R[b] && a < b);
}
};
set<int,cmp> S;
void Init() {
read(N);
for(int i = 0 ; i < (1 << N) ; ++i) {
read(A[i]);--A[i];
for(int j = 0 ; j < N ; ++j) {
if(!(i >> j & 1)) {
e[0][i].pb(i + (1 << j));
d[0][i + (1 << j)]++;
e[1][i + (1 << j)].pb(i);
d[1][i]++;
}
}
L[i] = 0;R[i] = (1 << N) - 1;
}
}
void Solve() {
L[0] = R[0] = 0;
for(int i = 0 ; i < (1 << N) ; ++i) {
if(A[i] != -1) L[i] = A[i];
int u = i;
for(auto v : e[0][u]) {
L[v] = max(L[v],L[u] + 1);
}
}
R[(1 << N) - 1] = L[(1 << N) - 1] = (1 << N) - 1; for(int i = (1 << N) - 1 ; i >= 0 ; --i) {
if(A[i] != -1) R[i] = A[i];
int u = i;
for(auto v : e[1][u]) {
R[v] = min(R[u] - 1,R[v]);
}
}
for(int i = 0 ; i < (1 << N) ; ++i) {
st[L[i]].pb(i);
}
for(int i = 0 ; i < (1 << N) ; ++i) {
for(auto t : st[i]) S.insert(t);
if(S.empty()) {puts("NO");return;}
int t = *S.begin();
S.erase(S.begin());
if(R[t] < i) {puts("NO");return;}
ans[t] = i;
} puts("YES");
for(int i = 1 , j = (1 << N - 1) ; i < (1 << N) - 1 ; ++i) {
if(i < j) swap(ans[i],ans[j]);
int k = (1 << N - 1);
while(j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
for(int i = 0 ; i < (1 << N) ; ++i) {
out(ans[i] + 1);space;
}
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

J - Tree MST

题解

好像直接点分可以爆艹

就是考虑点分每个点向别的子树里距离最短的点连边即可

然后直接kruskal

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N;
int64 X[MAXN];
struct node {
int to,next;int64 val;
}E[MAXN * 2];
int head[MAXN],sumE;
int que[MAXN],ql,qr,fa[MAXN],siz[MAXN],son[MAXN];
int64 dis[MAXN];
pair<int64,int> pre[MAXN],suf[MAXN];
vector<int> ver[MAXN];
bool vis[MAXN];
struct Enode {
int u,v;int64 c;
friend bool operator < (const Enode &a,const Enode &b) {
return a.c < b.c;
}
}edge[MAXN * 30];
int tot;
void add(int u,int v,int64 c) {
E[++sumE].to = v;
E[sumE].next = head[u];
E[sumE].val = c;
head[u] = sumE;
}
void Init() {
read(N);
for(int i = 1 ; i <= N ; ++i) read(X[i]);
int a,b;int64 c;
for(int i = 1 ; i < N ; ++i) {
read(a);read(b);read(c);
add(a,b,c);add(b,a,c);
}
}
int getfa(int u) {
return fa[u] == u ? u : fa[u] = getfa(fa[u]);
}
int Calc(int st) {
que[ql = qr = 1] = st;
fa[st] = 0;dis[st] = 0;
while(ql <= qr) {
int u = que[ql++];
siz[u] = 1;son[u] = 0;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && !vis[v]) {
que[++qr] = v;
fa[v] = u;
}
}
}
int res = que[qr];
for(int i = qr ; i >= 1 ; --i) {
int u = que[i];
if(fa[u]) {son[fa[u]] = max(son[fa[u]],siz[u]);siz[fa[u]] += siz[u];}
son[u] = max(son[u],qr - siz[u]);
if(son[u] < son[res]) res = u;
}
return res;
}
void dfs(int u) {
int G = Calc(u);
vis[G] = 1;
int cnt = 0;
dis[G] = 0;
for(int i = head[G] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {
++cnt;
ver[cnt].clear();
ver[cnt].pb(v);
fa[v] = G;dis[v] = dis[G] + E[i].val;
int s = 0;pair<int64,int> val = mp(dis[v] + X[v],v);
while(s < ver[cnt].size()) {
int n = ver[cnt][s];++s;
for(int k = head[n] ; k ; k = E[k].next) {
int h = E[k].to;
if(!vis[h] && h != fa[n]) {
fa[h] = n;
ver[cnt].pb(h);
dis[h] = dis[n] + E[k].val;
val = min(mp(dis[h] + X[h],h),val);
}
}
}
pre[cnt] = val;
suf[cnt] = val;
}
}
pre[0] = mp(1e18,0);
for(int i = 1 ; i <= cnt ; ++i) pre[i] = min(pre[i - 1],pre[i]);
suf[cnt + 1] = mp(1e18,0);
for(int i = cnt ; i >= 1 ; --i) suf[i] = min(suf[i + 1],suf[i]);
for(int i = 1 ; i <= cnt ; ++i) {
pair<int64,int> t = min(pre[i - 1],suf[i + 1]);
t = min(t,mp(X[G],G));
for(auto v : ver[i]) {
edge[++tot] = (Enode){v,t.se,t.fi + dis[v] + X[v]};
}
}
edge[++tot] = (Enode){G,pre[cnt].se,pre[cnt].fi + dis[G] + X[G]};
for(int i = head[G] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) dfs(v);
}
}
void Solve() {
dfs(1);
sort(edge + 1,edge + tot + 1);
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
int64 ans = 0;
int cnt = 0;
for(int i = 1 ; i <= tot ; ++i) {
if(getfa(edge[i].u) != getfa(edge[i].v)) {
ans += edge[i].c;
fa[getfa(edge[i].u)] = getfa(edge[i].v);
++cnt;
if(cnt == N - 1) break;
}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

【AtCoder】CODE FESTIVAL 2017 Final的更多相关文章

  1. 【Atcoder】CODE FESTIVAL 2017 qual A D - Four Coloring

    [题意]给定h,w,d,要求构造矩阵h*w满足任意两个曼哈顿距离为d的点都不同色,染四色. [算法]结论+矩阵变换 [题解] 曼哈顿距离是一个立着的正方形,不方便处理.d=|xi-xj|+|yi-yj ...

  2. 【Atcoder】CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning

    [题意]给定只含小写字母的字符串,要求分割成若干段使段内字母重组顺序后能得到回文串,求最少分割段数.n<=2*10^5 [算法]DP [题解]关键在于快速判断一个字符子串是否合法,容易发现合法仅 ...

  3. 【AtCoder】CODE FESTIVAL 2017 qual A

    A - Snuke's favorite YAKINIKU -- #include <bits/stdc++.h> #define fi first #define se second # ...

  4. 【AtCoder】CODE FESTIVAL 2017 qual B

    最近不知道为啥被安利了饥荒,但是不能再玩物丧志了,不能颓了 饥荒真好玩 A - XXFESTIVAL CCFESTIVAL #include <bits/stdc++.h> #define ...

  5. 【AtCoder】CODE FESTIVAL 2017 qual C

    A - Can you get AC? No #include <bits/stdc++.h> #define fi first #define se second #define pii ...

  6. 【AtCoder】CODE FESTIVAL 2016 qual A

    CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...

  7. 【AtCoder】CODE FESTIVAL 2016 qual B

    CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...

  8. 【AtCoder】CODE FESTIVAL 2016 qual C

    CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...

  9. 【赛时总结】 ◇赛时·IV◇ CODE FESTIVAL 2017 Final

    ◇赛时-IV◇ CODE FESTIVAL 2017 Final □唠叨□ ①--浓浓的 Festival 气氛 ②看到这个比赛比较特别,我就看了一看--看到粉粉的界面突然开心,所以就做了一下 `(* ...

随机推荐

  1. 自动化部署之搭建yum仓

    一.导言 YUM主要用于自动安装.升级rpm软件包,它能自动查找并解决rpm包之间的依赖关系.要成功的使用YUM工具安装更新软件或系统,就需要有一个包含各种rpm软件包的repository(软件仓库 ...

  2. 【洛谷P3916】图的遍历

    题目大意:给定一个 N 个点,M 条边的有向图,求每个点能够到达的节点的最大编号是多少. 题解:因为题中所给图不一定是一个 DAG,因此无法进行按照拓扑序来动态规划,需要另辟蹊径.由于求的是每个节点能 ...

  3. LeetCode 7最长公共前缀

    编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...

  4. [Leetcode]找到出现不同次数的数字(通用解法)

    今天在leetcode上遇到了 137. Single Number II 这道题: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次.找出那个只出现了一次的元素.(Give ...

  5. 转:iOS-生成Bundle包-引入bundle-使用bundle

    在我们使用第三方框架时,常常看到XXX.bundle的文件. 我们找到该文件,显示包内容,大致看到很多资源文件:图片.配置文本.XIB文件……   什么是Bundle文件? 简单理解,就是资源文件包. ...

  6. idea2017破解方法

    破解方法 切换license server然后 输入网址:http://idea.iteblog.com/key.php即可

  7. Linux遇到的问题(一)Ubuntu报“xxx is not in the sudoers file.This incident will be reported” 错误解决方法

    提示错误信息 www@iZ236j3sofdZ:~$ ifconfig Command 'ifconfig' is available in '/sbin/ifconfig' The command ...

  8. JavaScript的单线程性质以及定时器的工作原理

    前些日子还在网上争论过js动画用setTimeout还是setInterval,个人偏向于setTimeout,当动画中牵扯到ajax时用setInterval会有时间偏差,出现一些问题即使用clea ...

  9. 将网页设置为允许 XMLHttpRequest 跨域访问

    在非IE下,使用XMLHttpRequest 不能跨域访问, 除非要访问的网页设置为允许跨域访问. 将网页设置为允许跨域访问的方法如下: Java Response.AddHeader("A ...

  10. J2EE规范 - 13种规范

    J2EE是由SUN提出的用于简化开发企业级应用程序的一系列规范的组合,J2EE基于中间层集成的框架的方式为应用开发提供了一个统一的开发平台.基于容器管理.组件化的模型为企业建立一个高可用性,高可靠性可 ...