1.P1073——DAG
想法:
我的想法是tarjan求强连通分量之后dfs更新每个点的maxx(卖出价)(在这个节点买入),dfs应该是O(n)的。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
#define itn int
const int N = 1e5 + 5,M = 5e5 + 5;
int dfn[N],low[N],stac[N],head[N],h[N],val[N],bel[N],dp[N],minn[N],maxx[N];
int n,m,tot,cnt,ans,top,t,idx,u,v,z;
bool vis[N];
struct edge{
int v,next;
}e[M<<1],e2[M<<1];
inline void add(int u,int v){
e[++tot] = (edge){v,head[u]};
head[u] = tot;
}
inline void ad(int u,itn v){
e2[++t] = (edge){v,h[u]};
h[u] = t;
}
void tarjan(int u){
low[u] = dfn[u] = ++cnt;
stac[++top] = u;
vis[u] = true;
repe(i,u)
if(!dfn[e[i].v]){
tarjan(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(vis[e[i].v])
low[u] = min(low[u],dfn[e[i].v]);
if(low[u] == dfn[u]){
int cur;
idx++;
do {
cur = stac[top--];
vis[cur] = false;
bel[cur] = idx;
minn[idx] = min(minn[idx],val[cur]);
maxx[idx] = max(maxx[idx],val[cur]);
} while(cur != u);
}
}
void dfs(int u){
vis[u] = true;
for(int i = h[u];i;i = e2[i].next)
if(!vis[e2[i].v]) dfs(e2[i].v);
}
void dfs2(int u,int fa){
maxx[u] = max(maxx[u],maxx[fa]);
ans = max(ans,maxx[u] - minn[u]);
for(int i = h[u];i;i = e2[i].next)
if(vis[e2[i].v] && e2[i].v != fa) dfs2(e2[i].v,u);
}
int main(){
scanf("%d %d",&n,&m);
rep(i,n) scanf("%d",&val[i]);
rep(i,m){
scanf("%d %d %d",&u,&v,&z);
add(u,v);
if(z > 1) add(v,u);
}
rep(i,n) minn[i] = INT_MAX;
minn[0] = INT_MAX;
tarjan(1);
rep(i,n) repe(j,i) if(bel[i] != bel[e[j].v]) ad(bel[e[j].v],bel[i]);
dfs(bel[n]);
dfs2(bel[n],0);
printf("%d",ans);
return 0;
}
但是,TLE两个点。
我改了建边(判重),但是调试信息告诉我这算法远不是O(n)的,卡在了dfs2。
固执的80pts!!!
“正解”:
然而,我心中想当然的的DAG是这样的……
我没有想到DAG完全可以是这样的……
这就导致一个点可以被遍历好多次,复杂度远超预期。
这样就过了
#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i = 1;i <= n;i++)
#define repe(i,u) for(int i = head[u];i;i = e[i].next)
#define itn int
……
void dfs(int u,int fa){
maxx[u] = max(maxx[u],maxx[fa]);
ans = max(ans,maxx[u] - minn[u]);
vis[u] = true;
for(int i = h[u];i;i = e2[i].next)
if(!vis[e2[i].v]) dfs(e2[i].v,u);
}
map < pair <int,int>,bool> mp;
……
int main(){
read(n),read(m);
rep(i,n) read(val[i]);
rep(i,m){
read(u),read(v),read(z);
add(u,v);
if(z > 1) add(v,u);
}
rep(i,n) minn[i] = INT_MAX;
tarjan(1);
rep(i,n) repe(j,i) if(vi[i] && vi[e[j].v] && bel[i] != bel[e[j].v] && !mp[make_pair(bel[e[j].v],bel[i])])
ad(bel[e[j].v],bel[i]),mp[make_pair(bel[e[j].v],bel[i])] = true;
dfs(bel[n],0);
printf("%d",ans);
return 0;
}
后记:
其实这样还是错的,只是数据太水。
标记vis可能无法正确更新“maxx[u] = max(maxx[u],maxx[fa]);”。
正解是拓扑排序。
2.P2375——KMP
想法:
我的想法是:先求nxt数组,然后再判断是否重叠,重叠了继续往前跳j = nxt[j]
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define ll long long
const int N = 1e6 + 5,mod = 1e9 + 7;
int nxt[N],num[N],T,n,j,ans;
char s[N];
inline void read(int &x){
x = 0;
int f = 1;
char c;
for(c = getchar();!isdigit(c);c = getchar()) if(c == '-') f = -1;
for(;isdigit(c);c = getchar()) x = (x << 3) + (x <<1) + (c ^ 48);
x *= f;
}
inline void write(int x){
if(x < 0) x = -x,putchar('-');
if(x / 10) write(x / 10);
putchar((x % 10 + '0'));
}
void work(){
nxt[1] = j = 0,num[1] = 1;
n = strlen(s + 1);
rep(i,2,n){
while(j && s[i] != s[j+1]) j = nxt[j];
j += s[j+1] == s[i];
nxt[i] = j,num[i] = num[j] + 1;
}
ans = 1;
rep(i,2,n){
j = nxt[i];
while(j > i >> 1) j = nxt[j];
ans = ((ll)ans * (num[j] + 1)) % mod;
}
write(ans),putchar('\n');
}
int main(){
read(T);
while(T--){
scanf("%s",s + 1);
work();
}
return 0;
}
50ptsTLE QAQ
正解:
看了题解,好像没什么不同,除了我的第二个循环里的j = nxt[j]好像比它快一些?
事实打脸:改成题解那样就过了。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define ll long long
const int N = 1e6 + 5,mod = 1e9 + 7;
int nxt[N],num[N],T,n,j,ans;
char s[N];
inline void read(int &x){
x = 0;
int f = 1;
char c;
for(c = getchar();!isdigit(c);c = getchar()) if(c == '-') f = -1;
for(;isdigit(c);c = getchar()) x = (x << 3) + (x <<1) + (c ^ 48);
x *= f;
}
inline void write(int x){
if(x < 0) x = -x,putchar('-');
if(x / 10) write(x / 10);
putchar((x % 10 + '0'));
}
void work(){
nxt[1] = j = 0,num[1] = 1;
n = strlen(s + 1);
rep(i,2,n){
while(j && s[i] != s[j+1]) j = nxt[j];
j += s[j+1] == s[i];
nxt[i] = j,num[i] = num[j] + 1;
}
ans = 1,j = 0;
rep(i,2,n){
while(j && s[i] != s[j+1]) j = nxt[j];//注意这两行
j += s[j+1] == s[i];//
while(j > i >> 1) j = nxt[j];
ans = ((ll)ans * (num[j] + 1)) % mod;
}
write(ans),putchar('\n');
}
int main(){
read(T);
while(T--){
scanf("%s",s + 1);
work();
}
return 0;
}
百思不得其解
TLE的数据点:输入1e5个'a'
问了Cindy_Li学姐,她说:“你每次都要从i跳到i/2,给你一个aaaaaaaaa,你的做法就会被卡到n^2”
我输出了调试信息……果真如此
我只看到循环开始时j的值是一样的,但题解相当于在后面把j更新了,不用每次跳那么多步。这正是KMP的精髓所在啊,用失配信息计算答案
对kmp的理解加深了好多,考虑要全面