码迷,mamicode.com
首页 > 其他好文 > 详细

9.2题解

时间:2019-09-14 14:02:27      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:printf   sed   转移   splay   define   指针   name   pen   size   

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]{\leq}r]\sum\limits_{j=to[i]}^{r}(j-i)$

   $=\sum\limits_{i=l}^{r}[to[i]{\leq}r](-i{\times}(r-to[i]+1)+\sum\limits_{j=to[i]}^{r}j$

   $=\sum\limits_{i=l}^{r}[to[i]{\leq}r](to[i]{\times}i-i{\times}(r+1)+tot[r]-tot[to[i]-1])$

   $=\sum\limits_{i=l}^{r}[to[i]{\leq}r]to[i]{\times}i-(r+1){\times}\sum\limits_{i=l}^{r}[to[i]{\leq}r]i+tot[r]{\times}\sum\limits_{i=l}^{r}[to[i]{\leq}r]-\sum\limits_{i=l}^{r}[to[i]{\leq}r]tot[to[i]-1]$

这样看来的话我们是可以树状数组维护的,那么怎么处理$\sum\limits_{i=l}^{r}[to[i]{\leq}r]$这个条件的,很棒的一个方法,在树状数组中以$to[i]$为下标进行插入,开四个树状数组,一直查询就好了,那么当前我们只满足了$to[i]{\leq}r$,怎么满足$i{\geq}l$这个条件的?在树状数组中不停的清理不符合条件的$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题解

标签:printf   sed   转移   splay   define   指针   name   pen   size   

原文地址:https://www.cnblogs.com/hzjuruo/p/11518788.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!