1.19模拟赛总结

目录

1.19模拟赛总结


吐槽

MD,考场上被T1的DP搞到懵逼,最后30滚粗。还是要提高自己的\(dp​\)水平啊

以下3题均来自【USACO18DEC】GOLD


T1 (luogu5124)

简单DP,但就是推不出方程

题意:把一个\(n​\)个数的数列分成若干组不超过\(k​\)个数的连续的序列。每组序列(假定为\(a_l...a_r​\))的贡献为\(k \times max(a_l...a_r)​\),求贡献最大值。

\(1 \le n \le 10^4,1 \le k \le 10^3\)

题解:

\(f_i​\)为前\(i​\)个数的最大贡献。则

\(\huge f_i=max(f_j+max(a_j...a_i))(i-k<j<i)​\)

代码也就20行,复杂度\(O(nk)​\)

#include<bits/stdc++.h>
using namespace std;
int n,a[110000],f[110000],k,w;
int main()
{
    cin>>n>>k;
    for (int i=1;i<=n;i++)
      cin>>a[i];
    for (int i=0;i<=n;i++)
    {
        int p=0;
        for (int j=i+1;j<=min(i+k,n);j++)
        {
            p=max(a[j],p);
            f[j]=max(f[i]+p*(j-i),f[j]);
        }
    }
    cout<<f[n]<<endl;
    return 0;
}

T2 (luogu5123)

容斥、\(map\)什么的。压根没往这方向想

题意:有\(N\)头奶牛,每头牛有5个各不相同的喜欢的冰淇淋口味(数字),如果两头奶牛有一个数字是相同的,那么称这两头奶牛“和谐“,求不和谐的奶牛对数。

数据范围:\(2 \le N \le 5 \times 10^4​\) 种类数\(\le 10^6​\)

题解:

考虑总对数-和谐对数即为答案。

求和谐对数,我们可以用容斥原理来求。将转化成的字符串用\(map\)维护,再用容斥瞎搞一下就可以了,具体见代码。

STL是个好东西

Warning:以下代码常数过大,请勿模仿

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int a[8];long long n,c,ans;
map<string,int> m;
inline string stos(int x)
{
    string st1;
    for (int i=1;x;x>>=1,i++)
    {
        if (x&1) 
        {
            int y=a[i];string st="";
            while (y)
            {
                st=(char)(y%10+48)+st;
                y/=10;
            }
            st1+=st+"+";
        }
    }
    return st1;//转字符串
}
void dfs(int x,int c,int be)
{
    string st=stos(x);
    if (m.find(st)==m.end())
    {
        m.insert(make_pair(st,0));
    }
    if (c%2) ans+=m[st];else ans-=m[st];
    m[st]++;
    for (int j=be+1;j<=5;j++)
      dfs(x|(1<<(j-1)),c+1,j);
   //枚举状态,并求出这一头奶牛的和谐对数
}
int main()
{
    cin>>n;
    for (register int i=1;i<=n;i++)
    {
        for (int j=1;j<=5;j++)
          scanf("%d",&a[j]);
        sort(a+1,a+6);
        for (register int j=1;j<=5;j++)
          dfs(1<<(j-1),1,j);
    }
    cout<<n*(n-1)/2 - ans<<endl;
    return 0;
}

凑合着看吧,在Luogu跑了\(13S​\)


T3 (luogu5122)

题意:

给定一张\(N\)个点\(M\)条边的无向图,有\(K\)个特殊点,经过第\(i\)个特殊点能把最短路减去一个值(不能叠加),求是否能经过一个至少特殊点,且最短路长度不超过原来的最短路的长度。

数据范围:$2 \le N \le 5 \times 10^4,1\le M \le 10^5 $

题目链接

题解:

考虑状态拆分,设\(f[x][0]\)为到第\(x\)个点且没有经过干草堆的最短路,\(f[x][1]\)为到第\(x\)个点且至少经过一个干草堆的最短路。松弛显然。最后若\(f[i][1] \ge f[i][0]\)则可以,反之亦然。

#include<bits/stdc++.h>
using namespace std;
int n,m,k,cc,to[500100],net[500100],fr[500000],len[500000],f[500300][2];
int u,v,l,p,w;int q[800300],vis[800000],dis[500000];
int flag[500000];
void addedge(int u,int v ,int l)
{
    cc++;
    to[cc]=v;net[cc]=fr[u];fr[u]=cc;len[cc]=l;
}
int main()
{
    cin>>n>>m>>k;
    for (int i=1;i<=m;i++)
    {
        cin>>u>>v>>l;
        addedge(u,v,l);
        addedge(v,u,l);
    }
    for (int i=1;i<=k;i++)
    {
        cin>>w>>p;
        dis[w]=max(dis[w],p);
    }
    int h=0,t=0;
    for (int i=1;i<=n;i++)
      f[i][0]=f[i][1]=2147483647/2,vis[i]=false;
    f[n][0]=0;
    if (dis[n]) f[n][1]=-dis[n];
    q[0]=n;vis[n]=true;
    while (h<=t)
    {
        int x=q[h];
        for (int i=fr[x];i;i=net[i])
        {
            int y=to[i];
            if (f[y][0]>f[x][0]+len[i]) 
            {
                f[y][0]=f[x][0]+len[i];
                if (!vis[y]) 
                {
                  t++;q[t]=y;vis[y]=true;
                }
            }
            if (dis[y]&&f[x][0]+len[i]-dis[y]<f[y][1])
            {
                f[y][1]=f[x][0]+len[i]-dis[y];
                if (!vis[y]) 
                {
                  t++;q[t]=y;vis[y]=true;
                }
            }
            if (f[x][1]+len[i]<f[y][1])
            {
                f[y][1]=f[x][1]+len[i];
                if (!vis[y]) 
                {
                  t++;q[t]=y;vis[y]=true;
                }
            }
        }
        vis[q[h]]=0;h++;
    }
    for (int i=1;i<n;i++)
    {
        if (f[i][0]>=f[i][1]) printf("1\n");else printf("0\n");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fmj123/p/10295441.html