

还是有点蠢。。。
多测没清空T3挂40。。。(只得了人口普查分20)
多测题要把样例复制粘两遍自测一下防止未清空出锅。
然而不算分。。。
其实到现在了算不算也不重要了吧。。。
T1:你相信引力吗
维护最大值关系:肉眼可见的单调栈/队列。(刚开始认为是栈,后来其实发现是一个队列)
环,经典套路,拆成两倍长的序列。
维护一个单调不增的单调栈,根据题目含义画画图,可以发现答案是:
对于当前点,从栈里第一个严格大于当前元素的值开始数,栈里有多少个元素。
暴力思路就是二分。
可以发现你找到的那个元素后面的部分都会被弹掉,所以一边弹一边计数即可。
特殊的一点是权值相同的,这部分不会被弹栈,但是对答案也有贡献。
所以在每个元素入栈的时候记录一下栈顶有几个连续相同的元素即可。
然后还要考虑找到第一个比当前元素大的元素,所以检查一下栈底的元素是否比当前元素大,如果大的话再累加1个答案。
然后还要考虑环拉成序列以后同一个位置的元素可能在栈里出现2次。
所以就不是栈了,是个队列。如果队首元素的下表就是当前的下标,那么就弹出。
弹出的时候要考虑它对“栈里连续相同元素数量”的影响。
还有一个问题,如果对于一对冰锥,它的优弧和劣弧都满足条件,那么它的答案会被计算两次。
如果最大值出现了k次,那么它对答案产生的多出的贡献就是$\frac{k(k-1)}{2}$
特别的,当k=1时,如果次大值出现了j次,那么多出的答案就是$j$
所以把多出的贡献减去就是最终答案。
细节较多。但是如果上述分类讨论都注意到了的话调试还是挺简单的。

1 #include<cstdio>
2 int read(){
3 register int p=0;register char ch=getchar();
4 while(ch<'0'||ch>'9')ch=getchar();
5 while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
6 return p;
7 }
8 int n,a[5000005],q[10000005],p[10000005],s[10000005],h=1,t,mx,se,tmx,tse;long long ans;
9 int main(){
10 freopen("jolyne.in","r",stdin);freopen("jolyne.out","w",stdout);
11 n=read();
12 for(int i=1;i<=n;++i)a[i]=read();
13 for(int i=1;i<=n;++i)
14 if(a[i]>mx)se=mx,tse=tmx,mx=a[i],tmx=1;
15 else if(a[i]==mx)tmx++;
16 else if(a[i]>se)se=a[i],tse=1;
17 else if(a[i]==se)tse++;
18 for(int i=1;i<=n;++i){
19 while(t>=h&&a[i]>q[t])t--;
20 if(t>=h&&q[t]==a[i])s[++t]=s[t-1]+1;else s[++t]=1;
21 q[t]=a[i];p[t]=i;
22 }
23 for(int i=1;i<=n;++i){int nt=0;
24 while(t>=h&&p[h]<=i)nt=a[i]==q[h],h++;
25 while(t>=h&&a[i]>q[t])t--,ans++;
26 if(t>=h&&q[t]==a[i])s[++t]=s[t-1]+1;else s[++t]=1;
27 q[t]=a[i];p[t]=n+i;
28 if(h==t||q[h]!=q[t])nt=0;
29 s[t]-=nt;ans+=s[t]-1;if(q[h]!=a[i])ans++;
30 // for(int j=h;j<=t;++j)printf("%3d ",q[j]);puts("");
31 // for(int j=h;j<=t;++j)printf("%3d ",s[j]);puts("");
32 // printf("%lld\n",ans);
33 }
34 if(tmx==1)ans-=tse;
35 else ans-=tmx*(tmx-1ll)/2;
36 printf("%lld\n",ans);
37 }
T2:停不下来的团长奥尔加
比较明显的线性递推。
可以根据每个点的出度/入度平衡来做。
出度分为去右边的和去左边的,入度也是。
然后就可以递推了。

1 #include<cstdio>
2 #define mod 1000000007
3 int n,to[1000005];long long ans,oR[1000005],oL[1000005],iL[1000005],iR[1000005];
4 int main(){
5 freopen("rideon.in","r",stdin);
6 freopen("rideon.out","w",stdout);
7 scanf("%d",&n);
8 for(int i=1;i<=n;++i)scanf("%d",&to[i]);
9 iL[n+1]=1;
10 for(int i=n;i;--i){
11 oR[i]=iL[i+1];
12 oL[i]=oR[i];
13 iR[to[i]]=(iR[to[i]]+oL[i])%mod;
14 iL[i]=(oR[i]+oL[i]-iR[i]+mod)%mod;
15 ans=(ans+iL[i]+iR[i])%mod;
16 }printf("%lld\n",ans);
17 }
T3:Lesson5!
这题为什么要多测啊啊啊?一定要记得清空不然调到死。
建超级源汇会好做一些。(不建也可以,区别不大)
先预处理出来源点到每个点的距离f,以及每个点到汇点的距离g。
正反拓扑得到。
然后对于每一条边,经过它的最长路是fx+gy+1。称之为边的权值。
对于删除一个点,那么所有与它有关的边都不能贡献答案。
所以再一个正向拓扑,分层考虑所有点。
对于每一个点,删除所有入边的权值的贡献,此时出边的贡献还没有统计。
所以其实当前的状态下,就相当与删除了这个点时的状态,所以此时的最长路就是删掉这个点的最长路。
这个点考虑完之后就可以把它的出边都贡献答案了。
怎么求出答案?需要一个可以求最大值,可以删除的数据结构。
multiset。(于是我开始嘲笑出题人不会STL还要写权值线段树)
然后我被卡常了。。。
但是我坚决不打数据结构!所以就上priority_queue乱搞。
加一个懒惰删除即可。

1 #include<bits/stdc++.h>
2 using namespace std;
3 priority_queue<int>Q;
4 vector<int>v[100005];
5 int n,m,dp[100005],ans,ansp,cnt,fir[100005],l[700005],to[700005],deg[100005];
6 int f[100005],g[100005],q[100005],X[700005],Y[700005],delcnt[100005];
7 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;deg[b]++;}
8 int main(){
9 freopen("johnny.in","r",stdin);
10 freopen("johnny.out","w",stdout);
11 int T;scanf("%d",&T);
12 while(T--){
13 scanf("%d%d",&n,&m);
14 for(int i=0;i<=n+1;++i)fir[i]=f[i]=g[i]=0,v[i].clear();
15 while(!Q.empty())Q.pop();
16 ans=1234567890;cnt=0;
17 for(int i=1;i<=m;++i)scanf("%d%d",&X[i],&Y[i]),link(X[i],Y[i]);
18 for(int i=m+1;i<=m+n;++i)X[i]=0,Y[i]=i-m,link(X[i],Y[i]);
19 m+=n;
20 for(int i=m+1;i<=m+n;++i)X[i]=i-m,Y[i]=n+1,link(X[i],Y[i]);
21 m+=n;n++;
22 int t=0;
23 for(int i=0;i<=n;++i)if(!deg[i])q[++t]=i;
24 for(int h=1;h<=t;++h){
25 int p=q[h];
26 for(int i=fir[p];i;i=l[i]){
27 deg[to[i]]--;f[to[i]]=max(f[to[i]],f[p]+1);
28 if(!deg[to[i]])q[++t]=to[i];
29 }
30 }
31 t=0;for(int i=0;i<=n;++i)fir[i]=0;cnt=0;
32 for(int i=1;i<=m;++i)link(Y[i],X[i]);
33 for(int i=0;i<=n;++i)if(!deg[i])q[++t]=i;
34 for(int h=1;h<=t;++h){
35 int p=q[h];
36 for(int i=fir[p];i;i=l[i]){
37 deg[to[i]]--;g[to[i]]=max(g[to[i]],g[p]+1);
38 if(!deg[to[i]])q[++t]=to[i];
39 }
40 }
41 t=0;for(int i=0;i<=n;++i)fir[i]=0;cnt=0;
42 for(int i=1;i<=m;++i)link(X[i],Y[i]),v[Y[i]].push_back(1+g[Y[i]]+f[X[i]]);
43 for(int i=0;i<=n;++i)if(!deg[i])q[++t]=i;
44 Q.push(2);
45 for(int h=1;h<=t;++h){
46 int p=q[h];
47 for(int i=0;i<v[p].size();++i)delcnt[v[p][i]]++;
48 while(delcnt[Q.top()])delcnt[Q.top()]--,Q.pop();
49 if(Q.top()<ans&&p&&p!=n)ans=Q.top(),ansp=p;
50 if(Q.top()==ans&&p<ansp&&p)ansp=p;
51 for(int i=fir[p];i;i=l[i]){
52 deg[to[i]]--;Q.push(1+f[p]+g[to[i]]);
53 if(!deg[to[i]])q[++t]=to[i];
54 }
55 }
56 printf("%d %d\n",ansp,ans-2);
57 }
58 }
