1.19模拟赛总结
吐槽
MD,考场上被T1的DP搞到懵逼,最后30滚粗。还是要提高自己的(dp)水平啊
以下3题均来自【USACO18DEC】GOLD
T1 (luogu5124)
简单DP,但就是推不出方程。
题意:把一个(n)个数的数列分成若干组不超过(k)个数的连续的序列。每组序列(假定为(a_l...a_r))的贡献为(k imes 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 imes 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 imes 10^4,1le 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
");else printf("0
");
}
return 0;
}