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;
}
posted @ 2019-01-20 17:04  fmj_123  阅读(189)  评论(0编辑  收藏  举报