A. 黑色气球
数据保证答案唯一,则随便搞搞即可。
Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e3+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;
int n,h[MAXN][MAXN];
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>h[i][j];
}
}
int a = (h[1][2] + h[1][3] - h[2][3]) / 2;
cout <<a<<' ';
for(int i=2;i<=n;i++){
cout << h[1][i]-a<<" \n"[i==n];
}
return 0;
}
D. 求和
接下来是推式子时间:
\[ \begin{aligned} f(n)=&\sum_{i=1}^n\sum_{j=1}^ngcd(i,j,n)\\ =&\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j,n)=d]\\ =&\sum_{d=1}^nd\sum_{i=1}^n\sum_{j=1}^n[gcd(\frac{i}{d},\frac{j}{d},\frac{n}{d})=1]\\ =&\sum_{d=1}^nd\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}[gcd(i,j,\frac{n}{d})=1]\\ =&\sum_{d=1,d|n}^nd\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{n}{d}}\sum_{k|i,k|j,k|\frac{n}{d}}\mu(k)\\ =&\sum_{k}\mu(k)\sum_{d|n,d|\frac{n}{k}}(\frac{n}{kd})^2d\\ =&\sum_{T|n}(\frac{n}{T})^2\sum_{d|T}d\mu(\frac{T}{d})\\ =&\sum_{T|n}(\frac{n}{T})^2\varphi(T) \end{aligned} \]
故
\[ f(i)=\sum_{T|i}(\frac{i}{T})^2\varphi(T) \]
则
\[ \begin{aligned} \sum_{i=1}^nf(i)=&\sum_{i=1}^n\sum_{T|i}(\frac{i}{T})^2\varphi(T)\\ =&\sum_{T=1}^n\varphi(T)\sum_{i=1}^{\frac{n}{T}}i^2 \end{aligned} \]
所以杜教筛预处理\(\varphi\)的前缀和,然后整除分块即可。
代码如下:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 5;
int mu[N], p[N];
ll phi[N];
bool chk[N];
unordered_map <int, ll> mp1, mp2;
int MOD, inv6;
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
void init() {
inv6 = qpow(6, MOD - 2);
phi[1] = 1;
int cnt = 0, k = N - 1;
for(int i = 2; i <= k; i++) {
if(!chk[i]) p[++cnt] = i, mu[i] = -1, phi[i] = i - 1;
for(int j = 1; j <= cnt && i * p[j] <= k; j++) {
chk[i * p[j]] = 1;
if(i % p[j] == 0) {phi[i * p[j]] = phi[i] * p[j] % MOD; break;}
phi[i * p[j]] = phi[i] * (p[j] - 1) % MOD;
}
}
for(int i = 1; i < N; i++) {
phi[i] = (phi[i - 1] + phi[i]) % MOD;
}
}
ll djs_phi(int n) {
if(n <= 5000000) return phi[n];
if(mp2[n]) return mp2[n];
ll ans = 1ll * (n + 1) * n / 2 % MOD;
for(int i = 2, j; i <= n; i = j + 1) {
j = n / (n / i);
ans -= 1ll * (j - i + 1) * djs_phi(n / i) % MOD;
if(ans < 0) ans += MOD;
}
return mp2[n] = ans;
}
int n;
int S(int n) {
return 1ll * n * (n + 1) % MOD * (2 * n + 1) % MOD * inv6 % MOD;
}
int main() {
cin >> n >> MOD;
init();
int ans = 0;
for(int i = 1, j; i <= n; i = j + 1) {
j = n / (n / i);
int up = n / i;
int res = S(up);
ans = (ans + 1ll * res * (djs_phi(j) - djs_phi(i - 1) + MOD) % MOD) % MOD;
}
cout << ans << '\n';
return 0;
}
E. 棋技哥
存在一个结论,只要左上角为黑,则火山哥必胜。
因为火山哥赢的充要条件为游戏最终进行奇数轮就结束,那么必然\((1,1)\)初始为黑才行。
Code
#include<bits/stdc++.h>
using namespace std;
char s[2333];
int main() {
int t; scanf("%d", &t);
while(0<t--) {
bool ac=false;
int n,m; scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) {
scanf("%s", s);
if(i==0 && s[0]=='1') ac=true;
}
if(ac) puts("call");
else puts("aoligei");
}
return 0;
}
F. 社团管理
决策单调性\(dp\),还不会,填坑。
Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e5+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;
int n,k,a[MAXN],c[MAXN];
ll f[MAXN],g[MAXN];
void solve(int l,int r,int L,int R,ll w){
if(l>r)return ;
int m = (l+r)>>1,k=0,p=m<R?m:R;
for(int i=l;i<=m;i++)w+=c[a[i]]++;
for(int i=L;i<=p;i++){
w-=--c[a[i]];
if(l== n&& r==n){
//cout <<n<<' '<<i<<' '<<f[i]<<' '<<w<<'\n';
}
if(g[m] > f[i] + w){
g[m] = f[i] + w;
k=i;
}
}
for(int i=L;i<=p;i++){
w += c[a[i]]++;
}
for(int i=l;i<=m;i++)w-=--c[a[i]];
solve(l,m-1,L,k,w);
for(int i=l;i<=m;i++)w+=c[a[i]]++;
for(int i=L;i<k;i++)w-=--c[a[i]];
solve(m+1,r,k,R,w);
for(int i=L;i<k;i++)++c[a[i]];
for(int i=l;i<=m;i++)--c[a[i]];
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
f[i] = f[i-1] + c[a[i]]++;
}
memset(c,0,sizeof(c));
while(--k){
memset(g,0x3f,sizeof(g));
solve(1,n,1,n,0);
swap(f,g);
}
cout<<f[n]<<'\n';
return 0;
}
G. 火山哥周游世界
容易分析,最终火山哥的路线会经历每条必走的边两次,某条链可以只经过一次。
那么直接换根\(dp\)处理出离所有结点长度最长的链。之后再换根\(dp\)求出每个结点作为根时,到达所有关键点的边权和乘以\(2\)的值。二者相减即为每个结点作为根时的情况。
代码实现起来较为复杂,细节见代码。主要是维护最长链时要维护最长和次长链,这样就比较方便转移。
Code
/*
* Author: heyuhhh
* Created Time: 2020/1/14 14:23:18
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e5 + 5;
int n, k;
struct Edge {
int v, w, next;
}e[N << 1];
int head[N], tot;
void adde(int u, int v, int w) {
e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;
}
bool chk[N];
int sz[N];
ll f[N][2], g[N][2], L[N];
ll ans[N];
void dfs(int u, int fa) {
sz[u] = (chk[u] == true);
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if(v == fa) continue;
dfs(v, u);
sz[u] += sz[v];
}
}
void dfs2(int u, int fa) {
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if(v == fa) continue;
dfs2(v, u);
if(sz[v]) {
ans[u] += ans[v] + w;
if(f[v][0] + w > f[u][0]) {
f[u][1] = f[u][0];
g[u][1] = g[u][0];
f[u][0] = f[v][0] + w;
g[u][0] = v;
} else if(f[v][0] + w > f[u][1]) {
f[u][1] = f[v][0] + w;
g[u][1] = v;
}
}
}
}
void dfs3(int u, int fa, ll h) {
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if(v == fa) continue;
ll mx;
if(g[u][0] == v) mx = max(h, f[u][1]);
else mx = max(h, f[u][0]);
L[v] = max(f[v][0], mx + w);
dfs3(v, u, mx + w);
}
}
void dfs4(int u, int fa) {
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v, w = e[i].w;
if(v == fa) continue;
ans[v] = ans[u] - 2ll * (sz[v] > 0) * w + 2ll * (k - sz[v] > 0) * w;
dfs4(v, u);
}
}
void run(){
memset(head, -1, sizeof(head)); tot = 0;
for(int i = 1; i < n; i++) {
int u, v, w; cin >> u >> v >> w;
adde(u, v, w); adde(v, u, w);
}
for(int i = 1; i <= k; i++) {
int x; cin >> x;
chk[x] = 1;
}
dfs(1, 0);
dfs2(1, 0);
L[1] = f[1][0];
dfs3(1, 0, 0);
ans[1] <<= 1;
dfs4(1, 0);
for(int i = 1; i <= n; i++) ans[i] -= L[i];
for(int i = 1; i <= n; i++) cout << ans[i] << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
while(cin >> n >> k) run();
return 0;
}