学大伟业Day1解题报告
张炳琪
一. 时间分配
T1:30分钟 T2: 60分钟 T3:100分钟
二.答题情况及错因
T1:100 T2:55 T3:0
T1:刚开始想枚举的方法,后来发现时间复杂度好像是对的,就那样写了
T2:对数据范围判断不准确,刚开始打算用set盼重怕炸空间,后来又改成了数组结果改错了
T3:看到题目知道是树形dp,然后推了一个多小时的转移方程,写了一张多纸,没推出来
在有大题不会的情况下,要先保证能拿到的分拿到,不然做不出来大题就很吃亏
三.题目解析
T1:
暴力维护两个点的链接可以发现在两个英文字母形成的区间里面至多每个字母只能与他形成一个交叉点
那么我们从右到左枚举每个字母出现的区间直到发现与之交叉的或者右边界超出了控制范围(这个也可以二分,但是实际复杂度并不好)
T2:
增加了限制条件的最短路
首先数据范围是吓唬人的,两千条边用 100000000限速器没有任何用处
5000 * 2000 的visited数组用来判重
然后spfa 中间两种转移,队列中记录下当前用了多少加速器 ,一种转移耗费加速器 一种不耗费
T3:
四.代码
T1:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #define MAXN 101000 using namespace std; int ln[27][MAXN]; int rn[27][MAXN]; int top[27]; char s[MAXN]; int ans = 0; int main() { freopen("cross.in","r",stdin);freopen("cross.out","w",stdout); scanf("%s",s + 1); int len = strlen(s + 1); for(int i = 1; i <= len; i++) { s[i] = s[i] - 'a' + 1; if(ln[s[i]][top[s[i]]] == 0) { ln[s[i]][top[s[i]]] = i; } else if(rn[s[i]][top[s[i]]] == 0) { rn[s[i]][top[s[i]]] = i; for(int j = 1; j <= 26; j++) { if(j == s[i])continue; for(int k = top[j] - 1; k >= 0; k--) { if(ln[j][k] < ln[s[i]][top[s[i]]] && rn[j][k] > ln[s[i]][top[s[i]]]) { ans++; break; } if(rn[j][k] < ln[s[i]][top[s[i]]]) break; } } top[s[i]]++; } } printf("%d",ans); return 0; }
#include<queue> #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define MAXN 5010 using namespace std; struct Edge { int vj; int wei; int nxt; } edge1[MAXN * 4],edge2[MAXN * 4]; int now1,now2; int head1[MAXN],head2[MAXN]; struct Note { int now; int used; } be; queue<Note>q; void push1(int vi,int vj,int wei) { now1++; edge1[now1].vj = vj; edge1[now1].wei = wei; edge1[now1].nxt = head1[vi]; head1[vi] = now1; } void push2(int vi,int vj,int wei) { now2++; edge2[now2].vj = vj; edge2[now2].wei = wei; edge2[now2].nxt = head2[vi]; head2[vi] = now2; } int read() { int nm = 0; char c = getchar(); while(c < '0' || c > '9')c = getchar(); while(c >= '0' && c <= '9') { nm *= 10; nm += c -'0'; c = getchar(); } return nm; } int n,m,qq,k; int dis[MAXN][2050]; bool vis[MAXN][2050]; int main() { freopen("move.in","r",stdin); freopen("move.out","w",stdout); n = read(); m = read(); qq = read(); k = read(); if(k > qq)k = qq; for(int i = 1; i <= m; i++) { int vi = read(),vj = read(),wei = read(); push1(vi,vj,wei); } for(int i = 1; i <= qq; i++) { int vi = read(),vj = read(),wei = read(); push2(vi,vj,wei); } memset(dis,0x3e,sizeof(dis)); dis[1][0] = 0; be.now = 1; be.used = 0; q.push(be); while(!q.empty()) { Note op = q.front(); q.pop(); vis[op.now][op.used] = false; int now = op.now; int us = op.used; for(int i = head1[now]; i; i = edge1[i].nxt) { int vj = edge1[i].vj; if(dis[now][us] + edge1[i].wei < dis[vj][us]) { dis[vj][us] = dis[now][us] + edge1[i].wei; Note zz; zz.used = op.used; zz.now = vj; if(vis[zz.now][zz.used])continue; vis[zz.now][zz.used] = true; q.push(zz); } } if(op.used >= k)continue; for(int i = head2[now]; i; i = edge2[i].nxt) { int vj = edge2[i].vj; if(dis[now][us] + edge2[i].wei < dis[vj][us + 1]) { dis[vj][us + 1] = dis[now][us] + edge2[i].wei; Note zz; zz.used = op.used + 1; zz.now = vj; if(vis[zz.now][zz.used])continue; vis[zz.now][zz.used] = true; q.push(zz); } } } int ans = 0x3e3e3e3e; for(int i = 0; i <= min(k,qq); i++) { ans = min(ans,dis[n][i]); } printf("%d",ans == 0x3e3e3e3e ? -1:ans); return 0; }