• 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
    ",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=sumlimits_{i=l}^{r}[to[i]{leq}r]sumlimits_{j=to[i]}^{r}(j-i)$

       $=sumlimits_{i=l}^{r}[to[i]{leq}r](-i{ imes}(r-to[i]+1)+sumlimits_{j=to[i]}^{r}j$

       $=sumlimits_{i=l}^{r}[to[i]{leq}r](to[i]{ imes}i-i{ imes}(r+1)+tot[r]-tot[to[i]-1])$

       $=sumlimits_{i=l}^{r}[to[i]{leq}r]to[i]{ imes}i-(r+1){ imes}sumlimits_{i=l}^{r}[to[i]{leq}r]i+tot[r]{ imes}sumlimits_{i=l}^{r}[to[i]{leq}r]-sumlimits_{i=l}^{r}[to[i]{leq}r]tot[to[i]-1]$

    这样看来的话我们是可以树状数组维护的,那么怎么处理$sumlimits_{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
    ",ans[i]);
    76     return 0;
    77 }
    传参数组,我其实好久没试过了

    T3

    又是期望,成功咕咕咕

  • 相关阅读:
    vi常用操作
    Python练习题
    Jmeter也能IP欺骗!
    mysql主从配置
    性能测试之mysql监控、优化
    Git 命令
    Chrome——F12 谷歌开发者工具详解
    Appscan
    微信群发红包抢红包设计测试用例
    MySQL基础篇(1)SQL基础
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11518788.html
Copyright © 2020-2023  润新知