新高一蒟蒻队的第一次ACM……
赛场上和队友时间安排不太恰当……只过了9题,第10题差半个小时2333……/还是自己太弱了
赛后经过一段时间把所有题全部A掉了2333……
A:题目链接
这道题在聊天中开场7分钟A掉了2333……真的是签到题……直接输出n-1即可。证明略。
B:题目链接
这道题似乎也是比较水的吧……单调栈+dp裸题。
我们先找到每个点向上走最近的黑点到它的距离记为f(i,j)f(i,j)f(i,j),再考虑枚举合法矩形的右下角,并且找到满足k&lt;jk&lt;jk<j且f(i,j)&gt;=f(i,k)f(i,j)&gt;=f(i,k)f(i,j)>=f(i,k)的最大的k,这样对于当前合法的左端点<=k的矩形,必然和右下角再k的合法矩形一一对应,如果左端点>=k,答案就是f(i,j)∗(j−k)f(i,j)*(j-k)f(i,j)∗(j−k)。于是假设当前点答案为g(i,j)g(i,j)g(i,j),则g(i,j)=g(i,k)+f(i,j)∗(j−k)g(i,j)=g(i,k)+f(i,j)*(j-k)g(i,j)=g(i,k)+f(i,j)∗(j−k)。
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:题目链接
这道题大模拟不解释……(我居然用multiset写的,看来对stl依赖太多不是什么好事2333)

#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:题目链接
平面几何神题,qzr julao上来就想出来的题Orzzzzzz……
首先整个圆在凸包里可以转化为把凸包所有边向内移动半径的长度,然后圆心在新凸包里即可。新凸包用半平面交算一下就行。考虑最大价值是多少,拆一下项就会发现这个东西实际上是三个圆心构成三角形面积的两倍,然后旋转卡壳求凸包内最大三角形即可。复杂度O(Tn2)O(Tn^2)O(Tn2)。(qzr巨佬说他的代码暂时不给看2333)
E:题目链接
这道题就是给你一些依赖关系,然后最大化某个值,裸的状压dp,初始值注意一下就行。(具体的思路其它博客很多)
不过cy julao似乎非常喜欢记忆化搜索??

#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;
int dfs(int mask)
{if(vis[mask]) return dp[mask];vis[mask]=1;for(int i=0;i<n;i++){if(kl[i]&mask) continue;ll cc=k[i].first*has[mask]+k[i].second;if((need[i]&mask)==need[i]) dp[mask]=max(dp[mask],dfs(mask|kl[i])+cc);}//cout<<mask<<":"<<dp[mask]<<"  "; ans=max(ans,dp[mask]);dp[mask]=max(dp[mask],0ll);return dp[mask];
}
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(x)f(x)f(x)表示x节点回到root的期望边数,显然我们有f(root)=0.接下来考虑暴力的高斯消元(d(x)表示x的度数):
f(u)=(∑(u,v)∈Ef(v)/d(u))+1f(u)=\left(\sum_{(u,v)\in E}f(v)/d(u)\right)+1f(u)=⎝⎛​(u,v)∈E∑​f(v)/d(u)⎠⎞​+1
直接高消不现实,我们考虑它有什么特殊性质。考虑叶节点u,则f(u)=f(par)+1f(u)=f(par)+1f(u)=f(par)+1。对于倒数第二层节点u,则f(u)=f(par)+2d(u)−1f(u)=f(par)+2d(u)-1f(u)=f(par)+2d(u)−1,于是我们大胆假设,对于任意f(u)f(u)f(u),存在g(u)g(u)g(u)使f(u)=f(par)+g(u)f(u)=f(par)+g(u)f(u)=f(par)+g(u)。那么g(u)g(u)g(u)到底是什么呢?最后两层的规律告诉我们,g(u)=2s(u)−1g(u)=2s(u)-1g(u)=2s(u)−1,其中s(u)表示以u为根的子树大小。通过数学归纳法可以证明这个结论。
于是我们考虑答案是什么,由于第一步会任意走到根节点的一个子节点当中且不可能跳转到其它兄弟节点上,于是
ans=(∑(root,v)∈Ef(v)/d(root))+1=2s(root)−2d(root)ans=\left(\sum_{(root,v)\in E}f(v)/d(root)\right)+1=\frac{2s(root)-2}{d(root)}ans=⎝⎛​(root,v)∈E∑​f(v)/d(root)⎠⎞​+1=d(root)2s(root)−2​
即总节点个数的两倍-2再除以根节点度数。于是我们需要维护连通块中节点个数和每个节点的度数。后者是很好维护的,前者可以考虑LCT维护子树信息,每个节点记录一个值表示该节点所有非偏爱子树的大小之和,于是连通块大小就是根所在链的所有点的权值之和。LCT做一下就行了,复杂度O(nlogn)O(nlogn)O(nlogn)。

#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;
}
int link(int x, int y){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 fatheraccess(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 componentaccess(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;
char readc(){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 read(){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(){n = read(), m = read();for(int i = 1; i <= n; i++) sum[i] = val[i] = 1;for(int i = 1; i < n; i++) link(read(), read());for(int cs = 1; cs <= m; cs++){int a = read(), b = read(), c;if(a == 1){if(link(b, read()) < 0) prt[ppos++] = '-', prt[ppos++] = '1', prt[ppos++] = '\n';} else if(a == 2){c = read();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:题目链接
这道题考你的绝对是英语……那么长一个题面看了就要吐……
题目意思很简单,对于每个月我们不断找到当前灯数<=m的最前面的房间,这个东西在线段树上二分即可,复杂度O(nlogn)O(nlogn)O(nlogn)。

#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:题目链接
首先可以想到两种做法,一种是平衡树维护每个数字区间中元素出现次数(类似权值线段树),合并=启发式合并,查询直接跟线段树差不多,+1操作就直接加入一个长度为1的节点。但是瓶颈在于启发式合并的O(nlog2n)O(nlog^2n)O(nlog2n)。
一种是Trie直接维护二进制表示,查询直接往下遍历,合并=线段树合并,关键就在于如何处理+1操作。首先可以打标记,如果当前标记为奇数,那么交换左右子树并且交换后的左子树标记++,接下来无论奇数和偶数都加上当前标记>>1的值。
然后这道题就在O(nlogn)O(nlogn)O(nlogn)的时间内解决了。

#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;
char readc(){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 read(){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(){n = read(), m = read();for(int i = 1; i <= n; i++){root[i] = nd + (++tot);root[i]->cnt = 1;update(read(), DEP, root[i]);par[i] = i;}while(m--){int opt = read(), a = read(), b, c;if(opt == 1){b = read();if(find(a) == find(b)) continue;merge(root[find(a)], root[find(b)]);merge(a, b);} else if(opt == 3){b = read(), c = read();print(query(c, b, root[find(a)]));} else ++root[find(a)]->tag;}fwrite(prt, 1, ppos, stdout);return 0;
}

I:题目链接
这道题求所有本质不同回文串相加的和mod 1000000007,直接用回文树(回文自动机?)维护一下就行了,复杂度O(n)O(n)O(n)。

#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:题目链接
考虑对于每一个数都计算f(x),如果x的质因数分解中存在次数大于2的质因数,显然f(x)=0,如果有次数等于2的质因数直接忽略即可,于是就可以用线性筛筛出来,复杂度O(n)O(n)O(n)。
我太弱了,给我们队贡献了几个罚时,幸好qzr巨佬及时debug orz!!

#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:题目链接
这题真的可惜啊……cy巨佬已经想到做法了,可惜比赛中间发呆(分薯片?)了一会儿(雾)……
考虑每种个数的石子出现了多少次,由于f显然会出现一个循环,因此用高精度做一下就好了2333……接下来就到了dp时间,令f[i][j]表示所有个数<=i的堆中,异或和恰好为j的方案有多少种。我们会发现第i种个数有没有贡献仅仅取决于其取奇数堆还是偶数堆,也就是求:
(0n)+(2n)+(4n)+⋯\binom{0}{n}+\binom{2}{n}+\binom{4}{n}+\cdots(n0​)+(n2​)+(n4​)+⋯
可以证明这个玩意儿等于2n−12^{n-1}2n−1,于是用费马小定理+快速幂就可以算出来了,复杂度O(k2)O(k^2)O(k2)。

#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:题目链接
这道题是图论,还是比较水的吧……(完全靠stl的priority_queue跑得快2333)
考虑一个dp状态f[i][j]表示从1到i恰好修改j条路的最短路是多少,然后在Dijkstra(不敢写SPFA,怕被卡增加罚时)算最短路的时候更新一下dp就行了,复杂度O(TmKlogn)O(TmKlogn)O(TmKlogn)(我也不造咋跑过去的2333,反正就是800+msA掉了)

#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++){int u=v[t][i];int add=co[t][i];if(dp[u][ck]>dp[t][ck]+add){dp[u][ck]=dp[t][ck]+add;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]);}
}

然后整场预赛就结束了……总体来说发挥已经很不错了2333!

ACM-ICPC 2018 南京赛区网络预赛(ABCDEFGHIJKL所有题题解大全)相关推荐

  1. ACM-ICPC 2018 南京赛区网络预赛

    轻轻松松也能拿到区域赛名额,CCPC真的好难 An Olympian Math Problem 问答 只看题面 54.76% 1000ms 65536K Alice, a student of gra ...

  2. ACM-ICPC 2018 南京赛区网络预赛 Lpl and Energy-saving Lamps 线段树

    目录 ACM-ICPC 2018 南京赛区网络预赛 Lpl and Energy-saving Lamps 线段树 题面 题意 思路 ACM-ICPC 2018 南京赛区网络预赛 Lpl and En ...

  3. ACM-ICPC 2018 南京赛区网络预赛 B. The writing on the wall

    题目链接:https://nanti.jisuanke.com/t/30991 2000ms 262144K Feeling hungry, a cute hamster decides to ord ...

  4. ACM-ICPC 2018 南京赛区网络预赛 AC Challenge

    Dlsj is competing in a contest with n (0 < n \le 20)n(0<n≤20) problems. And he knows the answe ...

  5. ACM-ICPC 2018 南京赛区网络预赛 - AC Challenge(状压DP)

    ACM-ICPC 2018 南京赛区网络预赛 - AC Challenge 题意: 有n个题目,每个题目有一些信息,,第 t 个过第 i 题会得到分数 t*ai + bi 在过第 i 题前必须要先过  ...

  6. ACM-ICPC 2018 南京赛区网络预赛 E AC Challenge(状压dp)

    Dlsj is competing in a contest with n (0 < n \le 20)n(0<n≤20) problems. And he knows the answe ...

  7. E. AC Challenge ACM-ICPC 2018 南京赛区网络预赛 状压dp + 枚举状态

    博客目录 原题 题目链接 Dlsj is competing in a contest with n (0 < n \le 20)n(0<n≤20) problems. And he kn ...

  8. ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze 最短路+分层图

    类似题解 There are NN cities in the country, and MM directional roads from uu to v(1\le u, v\le n)v(1≤u, ...

  9. ACM-ICPC 2018 南京赛区网络预赛Sum,线性筛处理积性函数

    SUM 题意:f(n)是n可以拆成多少组n=a*b,a和b都是不包含平方因子的方案数目,对于a!=b,n=a*b和n=b*a算两种方案,求∑i=1nf(i) 首先我们可以知道,n=1时f(1)=1, ...

最新文章

  1. 浙江大学计算机考研大纲,2018年浙江大学研究生入学考试《计算机学科专业基础》(878)考试大纲...
  2. GraphQL 进阶: 基于Websocket的实时Web应用开发
  3. RocketMQ 千锤百炼--哈啰在分布式消息治理和微服务治理中的实践
  4. 如何将世界时钟和时区小部件添加到您的iPhone
  5. c#连mysql的latin1编码乱码问题
  6. 神经网络在游戏中的应用,神经网络控制应用实例
  7. n9 android rom,三星N935K官方固件rom刷机包_三星N935K线刷包_系统包下载
  8. 计算机显示磁盘但是打不开怎么办,移动硬盘显示盘符但打不开解决教程
  9. AndroidX全解析
  10. Travis CI(持续集成)
  11. iOS小技巧21-MacOS 苹果系统下Outlook打不开,显示“您需要最新版本的Outlook才能使用此数据库”
  12. linux mysql 超级用户_Linux下MySQL忘记超级用户口令的解决办法linux操作系统 -电脑资料...
  13. html里的常用特殊符号表示大全
  14. 暨南大学计算机专业考研录取目录,21考研必备 暨南大学2020计算机类研究生招生情况汇总...
  15. 我的JavaScript核心笔记
  16. Vue中定制公共组件之modal
  17. ⭐算法入门⭐《堆》中等02 —— LeetCode 703. 数据流中的第 K 大元素
  18. 骨传导蓝牙耳机哪个牌子好?目前好用的骨传导蓝牙耳机推荐
  19. 新视野大学英语(第三版)第二册课后翻译
  20. 在AGFA的一个月工作经历

热门文章

  1. 较快入门postman,使用postman玩转接口测试 一
  2. 【VSCode报错】 Error while fetching extensions : XHR failed
  3. 用Pandas分析了75w多条数据,揭秘美国选民的总统喜好!
  4. 计算机更改显卡,如何更换显卡
  5. 发现谁用 kill -9 关闭程序就开除!
  6. 前端性能优化方案都有哪些?
  7. 数字双向码的matlab仿真,matlab2016 ccs
  8. 软考高级 真题 2009年上半年 信息系统项目管理师 综合知识
  9. linux mv 文件夹不存在,linux 命令 mv abc.txt ../ 后文件不见了?
  10. 如何将Mac磁盘映像转换为其他格式?