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
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题解的主要内容,如果未能解决你的问题,请参考以下文章