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;
}