9.2题解

Posted hzjuruo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.2题解相关的知识,希望对你有一定的参考价值。

T1

考试打了个记忆化的暴搜,无线接近正解,然而没有想到换一种$dp$方式储存,去优化自己对于结果的优化,实际上稍微改一下就可以了

设$dp[i][j]$代表在第$i$个点用了$j$的时间所能经过的最多景点数,就在$dfs$中放一个$dp$转移就可以了,这种存$dp$值的方法也可以理解为记忆化搜索,记忆化是一个保证$dfs$时间复杂度的好途径

技术图片
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define maxv 2010
 5 #define maxm 510
 6 #define maxn 510
 7 #define maxe 5010
 8 #define inf 4557430888798830399
 9 #define int long long
10 using namespace std;
11 int v,m,n,e,l,r,c,ww;
12 int js,ans;
13 int ru[maxv],a[maxm],chu[maxv],b[maxn];
14 int head[maxv],to[maxe],xia[maxe],w[maxe];
15 int visit[maxv];
16 int dp[maxv][maxv];
17 void add(int x,int y,int z)
18 
19     to[++js]=y;  xia[js]=head[x];  w[js]=z;  head[x]=js;
20 
21 void dfs(int x)
22 
23     visit[x]=1;
24     for(int i=head[x];i;i=xia[i])
25     
26         int ls=to[i];
27         if(!visit[ls])  dfs(to[i]);
28         for(int j=1;j<=v;++j)
29         
30             if(dp[ls][j]<inf)  dp[x][j+1]=min(dp[x][j+1],dp[ls][j]+w[i]);
31             if(ru[x]&&dp[x][j+1]+a[ru[x]]<=l)  ans=max(ans,j+1);
32         
33     
34     if(chu[x])  dp[x][1]=min(dp[x][1],b[chu[x]]);
35 
36 main()
37 
38     scanf("%lld%lld%lld%lld%lld",&v,&m,&n,&e,&l);  memset(dp,0x3f,sizeof(dp));
39     for(int i=1;i<=m;++i)  scanf("%lld",&r);  scanf("%lld",&a[i]);  ru[r]=i;
40     for(int i=1;i<=n;++i)  scanf("%lld",&c);  scanf("%lld",&b[i]);  chu[c]=i;
41     for(int i=1;i<=e;++i)  scanf("%lld%lld%lld",&r,&c,&ww);  add(r,c,ww);
42         for(int i=1;i<=v;++i)
43         
44             if(chu[i]&&ru[i])  ans=max(ans,1ll*1);
45             if(!visit[i])  dfs(i);
46         
47     printf("%lld\n",ans);
48     return 0;
49 
View Code

T2

考场上打了一个$O(n^2)$的暴力,实际上非常好想,我的思路是找到每一个点对应的最近的一个可以满足不乏味的点,那么对于当前点来说,所有在找到的这个点前面的点都不可以,所有在这个点之后的都可以,这样的话我们就可以用$O(n^2)$的预处理,以及$O(n)$的回答水到很肥的部分分,当然了那个$O(n^2)$的预处理可以通过单调指针的优化变成$O(n)$,但由于询问的$O(n)$无法处理,加上$q$就是$O(n^2)$的时间复杂度,所以即使你快了很多,但仍然逃不过$T80$的命运

接下来是正解,我们先来一波疯狂推式子

设$to[i]$就是我刚才说的那个使以$i$为左端点的最小的不乏味区间的右端点

设$tot[i]$是1到i的和,等差公式,干就完了

然后进入正题

$ans=\sum\limits_i=l^r[to[i]\leqr]\sum\limits_j=to[i]^r(j-i)$

   $=\sum\limits_i=l^r[to[i]\leqr](-i\times(r-to[i]+1)+\sum\limits_j=to[i]^rj$

   $=\sum\limits_i=l^r[to[i]\leqr](to[i]\timesi-i\times(r+1)+tot[r]-tot[to[i]-1])$

   $=\sum\limits_i=l^r[to[i]\leqr]to[i]\timesi-(r+1)\times\sum\limits_i=l^r[to[i]\leqr]i+tot[r]\times\sum\limits_i=l^r[to[i]\leqr]-\sum\limits_i=l^r[to[i]\leqr]tot[to[i]-1]$

这样看来的话我们是可以树状数组维护的,那么怎么处理$\sum\limits_i=l^r[to[i]\leqr]$这个条件的,很棒的一个方法,在树状数组中以$to[i]$为下标进行插入,开四个树状数组,一直查询就好了,那么当前我们只满足了$to[i]\leqr$,怎么满足$i\geql$这个条件的?在树状数组中不停的清理不符合条件的$i$就可以了

技术图片
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #define int long long
 6 #define maxn 100100
 7 using namespace std;
 8 struct node
 9     int l,r,bh;
10 Q[maxn];
11 int n,m,q,tot,head=1,head1=1;
12 int a[maxn],to[maxn],kind[maxn];
13 int c1[maxn],c2[maxn],c3[maxn],c4[maxn],ans[maxn],pd[maxn];
14 bool cmp(const node &a,const node &b)
15 
16     return a.l<b.l;
17 
18 int lowbit(int x)
19 
20     return x&(-x);
21 
22 void add(int pos,int w,int a[])
23 
24     for(;pos<=n;pos+=lowbit(pos))  a[pos]+=w;
25 
26 int query(int pos,int a[])
27 
28     int ans=0;
29     for(;pos>0;pos-=lowbit(pos))  ans+=a[pos];
30     return ans;
31 
32 main()
33 
34     scanf("%lld%lld%lld",&n,&m,&q);
35     for(int i=1;i<=n;++i)  scanf("%lld",&a[i]);
36     for(int i=1;i<=q;++i)  scanf("%lld%lld",&Q[i].l,&Q[i].r);  Q[i].bh=i;
37     for(int i=1;i<=n;++i)
38     
39         if(tot<m)
40         
41             if(!kind[a[i]])  tot++;
42             kind[a[i]]++;
43         
44         while(tot==m)
45         
46             to[head]=i;  kind[a[head]]--;
47             if(!kind[a[head]])  tot--;
48             head++;
49         
50     
51     sort(Q+1,Q+q+1,cmp);  head=1;
52     for(int i=1;i<=q;++i)
53     
54         while(to[head]<=Q[i].r&&head<=n)
55         
56             if(to[head]==0)  head++;  continue;
57             if(head<Q[i].l)  head++;  continue;
58             add(to[head],to[head]*head,c1);  add(to[head],head,c2);
59             add(to[head],1,c3);  add(to[head],to[head]*(to[head]-1)/2,c4);
60             pd[head]=1;  head++;
61         
62         while(head1<Q[i].l&&head1<=n)
63         
64             if(!pd[head1])  head1++;  continue;
65             add(to[head1],-to[head1]*head1,c1);  add(to[head1],-head1,c2);
66             add(to[head1],-1,c3);  add(to[head1],-to[head1]*(to[head1]-1)/2,c4);
67             head1++;
68         
69         int ls1=query(Q[i].r,c1)-query(max(Q[i].l,to[Q[i].l])-1,c1);
70         int ls2=query(Q[i].r,c2)-query(max(Q[i].l,to[Q[i].l])-1,c2);
71         int ls3=query(Q[i].r,c3)-query(max(Q[i].l,to[Q[i].l])-1,c3);
72         int ls4=query(Q[i].r,c4)-query(max(Q[i].l,to[Q[i].l])-1,c4);
73         ls2=ls2*(Q[i].r+1);  ls3=ls3*Q[i].r*(Q[i].r+1)/2;  ans[Q[i].bh]=ls1-ls2+ls3-ls4;
74     
75     for(int i=1;i<=q;++i)  printf("%lld\n",ans[i]);
76     return 0;
77 
传参数组,我其实好久没试过了

T3

又是期望,成功咕咕咕

以上是关于9.2题解的主要内容,如果未能解决你的问题,请参考以下文章

正睿2018暑假集训 比赛题选做

双周赛 52,单周赛 241 题解

精LintCode领扣算法问题答案:入门

题解目录

[题解]noip杂题题解

BZOJ1798题解 Seq维护序列题解 双tag裸线段树