# ACM-ICPC 2018 南京赛区网络预赛（ABCDEFGHIJKL所有题题解大全）

A：题目链接

B：题目链接

f和g都可以直接dp出来，最大的k也可以单调栈找一下，然后就做完了（刚开始看AC人数少没敢做2333……）

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 100005, maxm = 105;
int f[maxm], sta[maxm], T, n, m, K;
bool mt[maxn][maxm];
ll dp[maxm];
int main(){
scanf("%d", &T);
for(int cs = 1; cs <= T; cs++){
memset(mt, 0, sizeof(mt));
memset(f, 0, sizeof(f));
memset(dp, 0, sizeof(dp));
scanf("%d%d%d", &n, &m, &K);
for(int i = 1; i <= K; i++){
int x, y; scanf("%d%d", &x, &y);
mt[x][y] = 1;
}
ll res = 0;
for(int i = 1; i <= n; i++){
int tp = 0;
for(int j = 1; j <= m; j++){
if(mt[i][j]) f[j] = 0;
else ++f[j];
while(tp > 0 && f[sta[tp]] >= f[j]) --tp;
if(f[j]){
dp[j] = dp[sta[tp]] + (ll)f[j] * (j - sta[tp]);
res += dp[j];
} else dp[j] = 0;
sta[++tp] = j;
}
}
printf("Case #%d: %lld\n", cs, res);
}
return 0;
}


C：题目链接

#include <bits/stdc++.h>
using namespace std;

const int maxn = 205;
multiset<int> ss[maxn];
int sta[20005], T, n, m;
const int rnk[15] = {0, 12, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
const int id[15] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2};
int main(){
scanf("%d", &T);
for(int cs = 1; cs <= T; cs++){
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++)
scanf("%d", sta + (m - i + 1));
int tp = m;
for(int i = 1; i <= n; i++){
ss[i].clear();
int k = min(5, tp);
for(int j = 0; j < k; j++)
ss[i].insert(rnk[sta[tp--]]);
}
int p = 1, t = 0, num = -1;
while(true){
if(t == n - 1){
for(int i = 0; i < n; i++){
if(tp == 0) break;
int k = (i + p - 1) % n + 1;
ss[k].insert(rnk[sta[tp--]]);
}
num = -1;
}
int flag = 0;
if(num == -1){
num = *ss[p].begin();
ss[p].erase(ss[p].begin());
} else if(ss[p].find(num + 1) != ss[p].end()){
ss[p].erase(ss[p].find(++num));
} else if(ss[p].find(13) != ss[p].end())
ss[p].erase(ss[p].find(num = 13));
else flag = 1;
if(flag) ++t;
else t = 0;
if(ss[p].empty()) break;
if(num == 13){
for(int i = 0; i < n; i++){
if(tp == 0) break;
int k = (i + p - 1) % n + 1;
ss[k].insert(rnk[sta[tp--]]);
}
num = -1;
} else p = p % n + 1;
}
printf("Case #%d:\n", cs);
for(int i = 1; i <= n; i++){
if(ss[i].empty()) puts("Winner");
else{
int sum = 0;
for(multiset<int>::iterator it = ss[i].begin(); it != ss[i].end(); it++)
sum += id[*it];
printf("%d\n", sum);
}
}
}
return 0;
}


D：题目链接

E：题目链接

#include<bits/stdc++.h>
#define pii pair< int,int>
#define ll long long
#define pll pair<long long,long long>
using namespace std;
int buf[80];
template<class T> inline bool getd(T& x){
int ch=getchar();
bool neg=false;
while(ch!=EOF && ch!='-' && !isdigit(ch)) ch=getchar();
if(ch==EOF) return false;
if(ch=='-'){
neg=true;
ch=getchar();
}
x=ch-'0';
while(isdigit(ch=getchar())) x=x*10+ch-'0';
if(neg) x=-x;
return true;
}

template<class M> inline void putd(M x)
{
int p=0;
if(x<0){
putchar('-');
x=-x;
}
do{
buf[p++]=x%(ll)10;
x/=(ll)10;
}while(x);
for(int i=p-1;i>=0;i--) putchar(buf[i]+'0');
putchar('\n');
}
int n;
ll inf=0x3f3f3f3f3f3f3f3f;
ll dp[1<<20];pii k[25];int need[25];int kl[25];int vis[1<<20];
int has[1<<20];ll ans=0;
{
for(int i=0;i<n;i++)
{
}
}
int main()
{
getd(n);for(int i=0;i<22;i++) kl[i]=(1<<i);
for(int i=0;i<(1<<20);i++) has[i]=__builtin_popcount(i)+1;
for(int i=0;i<n;i++)
{
getd(k[i].first);getd(k[i].second);
int tot;getd(tot);
while(tot--)
{
int id;getd(id);id--;need[i]|=kl[id];
}
}
dfs(0);
putd(ans);
}


F：题目链接

$f(u)=\left(\sum_{(u,v)\in E}f(v)/d(u)\right)+1$

$ans=\left(\sum_{(root,v)\in E}f(v)/d(root)\right)+1=\frac{2s(root)-2}{d(root)}$

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 100005, mod = 998244353;
int fa[maxn], rev[maxn], son[maxn][2], val[maxn], sum[maxn];
int du[maxn], n, m;
int isroot(int x){
return !fa[x] || (son[fa[x]][0] != x && son[fa[x]][1] != x);
}
void pushup(int x){
sum[x] = val[x] + sum[son[x][0]] + sum[son[x][1]];
}
void pushdown(int x){
if(!rev[x]) return;
rev[son[x][0]] ^= 1;
rev[son[x][1]] ^= 1;
rev[x] = 0;
swap(son[x][0], son[x][1]);
}
void rotate(int x){
int y = fa[x], z = fa[y], w = son[y][0] == x;
if(son[x][w]) fa[son[x][w]] = y;
if(!isroot(y)) son[z][son[z][1] == y] = x;
fa[y] = x, fa[x] = z;
son[y][!w] = son[x][w], son[x][w] = y;
pushup(y);
}
void splay(int x){
stack<int> sta;
sta.push(x);
for(int i = x; !isroot(i); i = fa[i]){
sta.push(fa[i]);
assert(fa[i] != i);
}
while(!sta.empty()) pushdown(sta.top()), sta.pop();
while(!isroot(x)){
int y = fa[x], z = fa[y];
if(!isroot(y)){
if(son[z][0] == y ^ son[y][0] == x) rotate(x);
else rotate(y);
} rotate(x);
}
pushup(x);
}
void access(int x){
for(int t = 0; x; t = x, x = fa[x]){
splay(x);
val[x] = val[x] - sum[t] + sum[son[x][1]];
son[x][1] = t;
pushup(x);
}
}
void makeroot(int x){
access(x), splay(x);
rev[x] ^= 1;
}
int findroot(int x){
access(x), splay(x);
pushdown(x);
while(son[x][0]){
x = son[x][0];
pushdown(x);
}
return x;
}
makeroot(x);
if(findroot(y) == x) return -1;
val[y] += sum[x];
pushup(y);
fa[x] = y;
++du[x], ++du[y];
return 0;
}
void cut(int x){//between x and its father
access(x), splay(x);
pushdown(x);
int f = son[x][0];
pushdown(f);
while(son[f][1]){
f = son[f][1];
pushdown(f);
}
--du[x], --du[f];
son[x][0] = fa[son[x][0]] = 0;
pushup(x);
}
int query(int x){//size of component
access(x);
splay(x);
return sum[x];
}
ll modpow(ll a, int b){
ll res = 1;
for(; b; b >>= 1){
if(b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
const int maxr = 10000000;
char str[maxr], prt[maxr];
int rpos, ppos, mmx;
if(!rpos) mmx = fread(str, 1, maxr, stdin);
if(rpos == mmx) return 0;
char c = str[rpos++];
if(rpos == maxr) rpos = 0;
return c;
}
int x; char c;
while((c = readc()) < '0' || c > '9');
x = c - '0';
while((c = readc()) >= '0' && c <= '9') x = x * 10 + c - '0';
return x;
}
int print(int x){
if(x){
static char sta[10];
int tp = 0;
for(; x; x /= 10) sta[tp++] = x % 10 + '0';
while(tp > 0) prt[ppos++] = sta[--tp];
} else prt[ppos++] = '0';
prt[ppos++] = '\n';
}
int main(){
for(int i = 1; i <= n; i++) sum[i] = val[i] = 1;
for(int cs = 1; cs <= m; cs++){
if(a == 1){
if(link(b, read()) < 0) prt[ppos++] = '-', prt[ppos++] = '1', prt[ppos++] = '\n';
} else if(a == 2){
if(findroot(b) != findroot(c) || b == c){
prt[ppos++] = '-', prt[ppos++] = '1', prt[ppos++] = '\n';
continue;
}
makeroot(b);
cut(c);
} else print((2LL * query(b) - 2) * modpow(du[b], mod - 2) % mod);
}
fwrite(prt, 1, ppos, stdout);
return 0;
}


G：题目链接

#include <bits/stdc++.h>
using namespace std;
int inf=0x3f3f3f3f;
const int nn = 65536*2;
int tree[nn*2+10];
int _update(int x,int y)
{
tree[x]=y;x=x/2;
while(x)
{
tree[x]=min(tree[x*2],tree[x*2+1]);
x=x/2;
}
}
int fix;
int _query(int l,int r,int id)
{
if(tree[id]>fix) return 0;if(l==r) return l;
if(tree[id*2]<=fix) _query(l,(l+r)/2,id*2);
else _query((l+r)/2+1,r,id*2+1);
}
int n,m;
pair<int,int> q[100008];
int main()
{
scanf("%d%d",&n,&m);memset(tree,inf,sizeof(tree));
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
_update(i+nn-1,x);
}
int flag=1;int ui=0;int alr=0;
for(int i=1;i<=100000;i++)
{
if(alr<n) ui+=m;
while(1)
{
fix=ui;
int t=_query(1,nn,1);
if(t)
{
ui-=tree[nn+t-1];
_update(nn+t-1,inf);alr++;
}
else break;
}
q[i]=make_pair(ui,alr);
}
int Q;scanf("%d",&Q);
while(Q--)
{
int t;scanf("%d",&t);
printf("%d %d\n",q[t].second,q[t].first);
}
return 0;
}


H：题目链接

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 600005, maxt = 20000005, DEP = 30;
struct Node{
Node *ls, *rs; int cnt, tag;
Node() : ls(0), rs(0), cnt(0), tag(0) {}
} nd[maxt];
int par[maxn], n, m, tot;
Node *root[maxn];
void pushdown(Node *x){
if(!x->tag) return;
if(x->tag & 1){
swap(x->ls, x->rs);
if(x->ls) ++x->ls->tag;
}
if(x->ls) x->ls->tag += x->tag >> 1;
if(x->rs) x->rs->tag += x->tag >> 1;
x->tag = 0;
}
Node* merge(Node *x, Node *y){
if(!y) return x;
if(!x) return y;
pushdown(x), pushdown(y);
x->cnt += y->cnt;
x->ls = merge(x->ls, y->ls);
x->rs = merge(x->rs, y->rs);
return x;
}
void update(int x, int d, Node *k){
if(!d) return;
if(x & 1){
if(!k->rs){
Node *p = nd + (++tot);
p->cnt = 1;
k->rs = p;
}
update(x >> 1, d - 1, k->rs);
} else {
if(!k->ls){
Node *p = nd + (++tot);
p->cnt = 1;
k->ls = p;
}
update(x >> 1, d - 1, k->ls);
}
}
int query(int x, int d, Node *k){
if(!k) return 0;
if(!d) return k->cnt;
pushdown(k);
if(x & 1) return query(x >> 1, d - 1, k->rs);
else return query(x >> 1, d - 1, k->ls);
}
int find(int x){return x == par[x] ? x : par[x] = find(par[x]);}
void merge(int x, int y){
x = find(x), y = find(y);
if(x != y) par[y] = x;
}
const int maxr = 10000000;
char str[maxr], prt[maxr];
int rpos, ppos, mmx;
if(!rpos) mmx = fread(str, 1, maxr, stdin);
if(rpos == mmx) return 0;
char c = str[rpos++];
if(rpos == maxr) rpos = 0;
return c;
}
int x; char c;
while((c = readc()) < '0' || c > '9');
x = c - '0';
while((c = readc()) >= '0' && c <= '9') x = x * 10 + c - '0';
return x;
}
int print(int x){
if(x){
static char sta[10];
int tp = 0;
for(; x; x /= 10) sta[tp++] = x % 10 + '0';
while(tp > 0) prt[ppos++] = sta[--tp];
} else prt[ppos++] = '0';
prt[ppos++] = '\n';
}
int main(){
for(int i = 1; i <= n; i++){
root[i] = nd + (++tot);
root[i]->cnt = 1;
par[i] = i;
}
while(m--){
if(opt == 1){
if(find(a) == find(b)) continue;
merge(root[find(a)], root[find(b)]);
merge(a, b);
} else if(opt == 3){
print(query(c, b, root[find(a)]));
} else ++root[find(a)]->tag;
}
fwrite(prt, 1, ppos, stdout);
return 0;
}


I：题目链接

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2000005, mod = 1000000007;
int son[maxn][9], len[maxn], num[maxn];
int pw[maxn], fail[maxn], n, tot, last;
char str[maxn];
void init(){
len[1] = -1;
fail[0] = 1;
tot = 1;
}
void extend(int x){
int p = last, c = str[x] - '1';
while(str[x - len[p] - 1] != str[x]) p = fail[p];
if(!son[p][c]){
int np = ++tot, q = fail[p];
len[np] = len[p] + 2;
if(len[np] == 1) num[np] = c + 1;
else num[np] = (num[p] * 10LL + (ll)pw[len[np] - 1] * (c + 1) + c + 1) % mod;
while(str[x - len[q] - 1] != str[x]) q = fail[q];
fail[np] = son[q][c];
son[p][c] = np;
}
last = son[p][c];
}
int main(){
scanf("%s", str + 1);
n = strlen(str + 1);
str[0] = '@';
str[n + 1] = '#';
pw[0] = 1;
for(int i = 1; i <= n; i++) pw[i] = pw[i - 1] * 10LL % mod;
init();
for(int i = 1; i <= n; i++) extend(i);
int res = 0;
for(int i = 2; i <= tot; i++) res = (res + num[i]) % mod;
printf("%d\n", res);
return 0;
}


J：题目链接

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 20000005, N = 20000000;
ll f[maxn];
int prime[2000005], vis[maxn], T;
int main(){
int cnt = 0;
f[1] = 1;
for(int i = 2; i <= N; i++){
if(!vis[i]){
prime[cnt++] = i;
f[i] = 2;
}
for(int j = 0; j < cnt; j++){
int p = prime[j], m = i * p;
if(m > N) break;
vis[m] = 1;
if(i % p == 0){
int d = i / p;
if(d % p == 0) f[m] = 0;
else f[m] = f[d];
break;
}
f[m] = f[i] * f[p];
}
}
for(int i = 1; i <= N; i++){
f[i] += f[i - 1];
}
scanf("%d", &T);
while(T--){
int n; scanf("%d", &n);
printf("%lld\n", f[n]);
}
return 0;
}


K：题目链接

$\binom{0}{n}+\binom{2}{n}+\binom{4}{n}+\cdots$

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1500005, maxm = 4100, mod = 1000000007;
const int Base = 1000000000, Digit = 9;
struct Bigint{
int num[maxn], n;
Bigint(){memset(num, 0, sizeof(num)); n = 0;}
Bigint(char *str){
int l = strlen(str);
memset(num, 0, sizeof(num));
n = 0;
for(int i = l - 1; i >= 0; i -= Digit){
int k = min(Digit, i + 1);
for(int j = i - k + 1; j <= i; j++)
num[n] = num[n] * 10 + str[j] - '0';
++n;
}
}
Bigint& operator-=(int x){
num[0] -= x;
for(int i = 0; i < n; i++){
if(num[i] < 0){
num[i] += Base;
--num[i + 1];
}
}
while(!num[n - 1]) --n;
return *this;
}
int operator/=(int x){
int rem = 0;
for(int i = n - 1; i >= 0; i--){
ll t = (ll)rem * Base + num[i];
num[i] = t / x;
rem = t % x;
}
return rem;
}
} big;
char str[maxn * 4];
int K, A, B, C, D, E, X1, cnt[maxm], f[2][maxm], vis[maxm];
void solve_small(){
int n = big.num[0];
memset(cnt, -1, sizeof(cnt));
for(int i = 0; i < n - 1; i++){
ll x = X1;
++cnt[X1];
X1 = ((((A * x + B) * x + C) * x + D) * x + E - 1) % K + 1;
}
++cnt[X1];
}
void solve_big(){
int n = 0;
while(true){
ll x = X1;
vis[x] = ++n;
X1 = ((((A * x + B) * x + C) * x + D) * x + E - 1) % K + 1;
if(vis[X1]) break;
}
if(vis[X1] > 1) big -= vis[X1] - 1;
int rem = big /= n - vis[X1] + 1;
int md = big /= mod - 1, md1 = (md - 1 + mod) % mod;
memset(cnt, -1, sizeof(cnt));
for(int i = 1; i <= K; i++) if(vis[i]){
if(vis[i] >= vis[X1]){
if(vis[i] < vis[X1] + rem) cnt[i] = md;
else cnt[i] = md1;
} else cnt[i] = 0;
}
}
ll modpow(ll a, int b){
ll res = 1;
for(; b; b >>= 1){
if(b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
int main(){
scanf("%s%d%d%d%d%d%d%d", str, &X1, &A, &B, &C, &D, &E, &K);
big = str;
if(big.n == 1 && big.num[0] <= K) solve_small();
else solve_big();
f[0][0] = 1;
for(int i = 1; i <= K; i++){
int *now = f[i & 1], *lst = f[~i & 1];
if(cnt[i] < 0){
for(int j = 0; j <= K; j++) now[j] = lst[j];
continue;
}
ll t = modpow(2, cnt[i]);
for(int j = 0; j <= K; j++)
now[j] = t * (lst[j] + lst[j ^ i]) % mod;
}
int res = 0;
for(int i = 1; i <= K; i++) res = (res + f[K & 1][i]) % mod;
printf("%d\n", res);
return 0;
}


L：题目链接

#include<bits/stdc++.h>
#define pii pair< int,int>
#define ll long long
#define pli pair<long long,int>
using namespace std;
int buf[80];
template<class T> inline bool getd(T& x){
int ch=getchar();
bool neg=false;
while(ch!=EOF && ch!='-' && !isdigit(ch)) ch=getchar();
if(ch==EOF) return false;
if(ch=='-'){
neg=true;
ch=getchar();
}
x=ch-'0';
while(isdigit(ch=getchar())) x=x*10+ch-'0';
if(neg) x=-x;
return true;
}

template<class M> inline void putd(M x)
{
int p=0;
if(x<0){
putchar('-');
x=-x;
}
do{
buf[p++]=x%(ll)10;
x/=(ll)10;
}while(x);
for(int i=p-1;i>=0;i--) putchar(buf[i]+'0');
putchar('\n');
}
int n,m,k;
ll inf=0x3f3f3f3f3f3f3f3f;
ll dp[100008][11];
vector<int> v[100008],co[100008];
int main()
{
int T;getd(T);
while(T--)
{
memset(dp,inf,sizeof(dp));
getd(n);getd(m);getd(k);
for(int i=1;i<=n;i++)
{
v[i].clear();co[i].clear();
}
while(m--)
{
int x,y,s;getd(x);getd(y);getd(s);
v[x].push_back(y);co[x].push_back(s);
}priority_queue<pli> nxt;
for(int ck=0;ck<=k;ck++)
{
dp[1][ck]=0;
priority_queue<pli> pq;swap(pq,nxt);
pq.push(make_pair(-0,1));
while(!pq.empty())
{
int t=pq.top().second;ll dist=pq.top().first;
pq.pop();
if(dist>dp[t][ck]) continue;
for(int i=0;i<v[t].size();i++)
{
{
pq.push(make_pair(-dp[u][ck],u));
}
if(dp[u][ck+1]>dp[t][ck])
{
dp[u][ck+1]=dp[t][ck];
nxt.push(make_pair(-dp[u][ck+1],u));
}
}
}
}
putd(dp[n][k]);
}
}