2019.03.23【NOIP提高组】模拟 A 组 比赛总结

总结&题解

今天炸车愉快!
在这里插入图片描述
得分=估分=20+30=50(水分代码打得准!)
T1:
从数据可看出此题要用 O ( n 2 ) O(n^2) O(n2)的方法去做,这是显然的。
然而怎么做?
比赛时我想到枚举第1,2座城市,用些预处理搞出3,4,发现不可行;枚举2,3的话,1和4又会有冲突应该也不是贪心能解决的;枚举1,3的话DP更麻烦。
于是我就打了个 O ( n 4 ) O(n^4) O(n4)的暴力,不用说,直接20分了。
其实正解就是第二种方案:枚举2,3( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)
先跑一次最短路,处理出每一个点所能到达的前三远的点(一会儿会解释为什么是三),然后把所有的边反过来连接,再跑一遍最短路,得出能到达每一个点的前三远的点。
那么为什么是三呢?假设当前确定的第2,3个点为a,b,第1,2个点为x,y,对于x,显然有 x ̸ = a , x ̸ = b , x ̸ = y x\not =a,x\not =b,x\not =y x̸=a,x̸=b,x̸=y,其中由于x是由a固定了,因此 x ̸ = a x\not =a x̸=a可以在初始化的时候判断。剩下有2中不等的情况,因此要存前三大。
最后枚举a,b,选前三个x,y一一匹配就可以了,时间复杂度 O ( n 2 ) O(n^2) O(n2)。这题还是相当容易的,看来比赛时应该仔细思考每一种方案。
P.S:此题其实SPFA即可,我却疑心数据卡SPFA,打了dijkstar+堆优化,白白调了半天。
T2:
总想着把边也转换成点,在图上乱搞,结果最后什么也没有想出来,只好暴力水分。
其实这道题目可以很巧妙地转换成二分图上的问题。
不妨枚举目标颜色(即最终每一条边都要变成哪一种颜色,这里假定为R),那么对于每一条边就有变换奇数次和偶数次的两种方案。对于一条颜色为B的边,要变换奇数次,因此就要把边连接的两个点在一个新的图中连上一条边;对于R就不操作。这样我们就得到了一个有若干条边、每条边表示两个点在两个不同集合内的图。这时,只用将某一集合内所有的点全部变换就可以了,因此可以用二分图染色
T3:
又是一道猥琐神奇的容斥题,比赛时果断放弃(;′⌒`)
其实光是子序列的定义就把我弄得半死,然而某DL却搞出来了!
由于题目要求最长公共子序列长度为n-1,因此只要从原串中取出一个字符,把它修改并插入到序列中的某一个位置(可以包括原位置)就可以了。
先不考虑重复。把某一个字母抽出来,有n个位置可以让它插入(把aaabbbcbac中标红的字母取出后,变成aaa bbcbac,原位置共有n个地方可插入),而它可以变m种字母,因此当前有 n × m n\times m n×m种情况。但是我们可以注意到aaabbcbacc与aaabbcbacc其实是等价的,而这种情况一定会出现n组。接着,不难发现,在一条连续的相同字母种,取出哪一个都是等价的,因此我们不妨把字母划分一下,相同的字母划在同一组(aaabbcbac变成|aaa|bb|c|b|a|c),这时对于每一组就对答案有 n × ( m − 1 ) n\times(m-1) n×(m1)的贡献。
然而这样还不够!
当我们碰到ababababab这种字符串(即第 i 个与第i-2个字符相等,且其中含有2种不同字符)时,把第3个a放到后一个位置会变成abbaababab,与把第4个放到前一个位置abbaababab是等价的。观察得出,这种序列中的每一个字符都会与前面的每一个字符有一次重复。设序列长为k,那么根据等差数列求和公式,就会有 k × ( k − 1 ) 2 \frac{k\times (k-1)}{2} 2k×(k1)种重复。
然后就可以了,实现还是相当容易的。

代码

T1

#include<cstdio>
using namespace std;
#define inf 999999999
#define fa k>>1
#define lson k<<1
#define rson k<<1|1
#define N 3005
#define M 5005
struct edge
{
    
    
	int end,next;
}a[M],b[M];
int bz[N],que[N],f[N][N],dis[N],first[N],last[N],ans[5],max[N][2][3][2],n,m,top;
inline void swap(int &a,int &b){
    
    a^=b,b^=a,a^=b;}
inline void up(int k)
{
    
    
	while(k>1&&dis[que[fa]]>dis[que[k]]) bz[que[fa]]=k,bz[que[k]]=fa,swap(que[fa],que[k]),k>>=1;
}
inline void down(int k)
{
    
    
	while(lson<=top&&(dis[que[k]]>dis[que[lson]]||rson<=top&&dis[que[k]]>dis[que[rson]]))
	{
    
    
		if(rson<=top&&dis[que[lson]]>dis[que[rson]]) bz[que[k]]=rson,bz[que[rson]]=k,swap(que[k],que[rson]),k=rson;
		else bz[que[k]]=lson,bz[que[lson]]=k,swap(que[k],que[lson]),k<<=1;
	}
}
inline void insert(int k){
    
    que[++top]=k,bz[k]=top,up(top);}
inline void update(int k){
    
    up(bz[k]);}
inline int Del(){
    
    int res=que[1];bz[que[top]]=1,que[1]=que[top--],down(1);return res;}
inline void dijkstar(int k)
{
    
    
	int i,j,u=0,v;
	for(i=1;i<=n;i++) dis[i]=inf,bz[i]=0;
	dis[k]=top=0,insert(k);
	for(j=1;j<n&&top;j++)
	{
    
    
		u=Del();
		if(dis[u]==inf) break;
		max[k][0][2][0]=max[k][0][1][0],max[k][0][2][1]=max[k][0][1][1];
		max[k][0][1][0]=max[k][0][0][0],max[k][0][1][1]=max[k][0][0][1];
		max[k][0][0][0]=dis[u],max[k][0][0][1]=u;
		for(i=first[u];i;i=a[i].next)
		{
    
    
			v=a[i].end;
			if(dis[v]>dis[u]+1)
			{
    
    
				dis[v]=dis[u]+1;
				if(bz[v]) update(v);
				else insert(v);
			}
		}
	}
	if(top)
	{
    
    
		u=Del();
		if(dis[u]<inf)
		{
    
    
			max[k][0][2][0]=max[k][0][1][0],max[k][0][2][1]=max[k][0][1][1];
			max[k][0][1][0]=max[k][0][0][0],max[k][0][1][1]=max[k][0][0][1];
			max[k][0][0][0]=dis[u],max[k][0][0][1]=u;
		}
	}
	for(i=1;i<=n;i++) f[k][i]=dis[i],dis[i]=inf,bz[i]=0;
	dis[k]=top=0,insert(k);
	for(j=1;j<n&&top;j++)
	{
    
    
		u=Del();
		if(dis[u]==inf) break;
		max[k][1][2][0]=max[k][1][1][0],max[k][1][2][1]=max[k][1][1][1];
		max[k][1][1][0]=max[k][1][0][0],max[k][1][1][1]=max[k][1][0][1];
		max[k][1][0][0]=dis[u],max[k][1][0][1]=u;
		for(i=last[u];i;i=b[i].next)
		{
    
    
			v=b[i].end;
			if(dis[v]>dis[u]+1)
			{
    
    
				dis[v]=dis[u]+1;
				if(bz[v]) update(v);
				else insert(v);
			}
		}
	}
	if(top)
	{
    
    
		u=Del();
		if(dis[u]<inf)
		{
    
    
			max[k][1][2][0]=max[k][1][1][0],max[k][1][2][1]=max[k][1][1][1];
			max[k][1][1][0]=max[k][1][0][0],max[k][1][1][1]=max[k][1][0][1];
			max[k][1][0][0]=dis[u],max[k][1][0][1]=u;
		}
	}
}
int main()
{
    
    
	int i,j,x,y,z;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) scanf("%d%d",&x,&y),a[i]=(edge){
    
    y,first[x]},b[i]=(edge){
    
    x,last[y]},last[y]=first[x]=i;
	for(i=1;i<=n;i++) dijkstar(i);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(i!=j&&f[i][j]<inf)
				{
    
    
					for(x=0;x<3;x++) if(max[i][1][x][1]!=j)
					{
    
    
						for(y=0;y<3&&(max[i][1][x][1]==max[j][0][y][1]||max[j][0][y][1]==i);y++);
						if(y<3&&max[j][0][y][1]&&(z=max[i][1][x][0]+max[j][0][y][0]+f[i][j])>ans[0])
							ans[0]=z,ans[1]=max[i][1][x][1],ans[2]=i,ans[3]=j,ans[4]=max[j][0][y][1];
					}
				}
	printf("%d %d %d %d\n",ans[1],ans[2],ans[3],ans[4]);
	return 0;
}

T2

#include<cstdio>
#include<cstring>
using namespace std;
#define N 100005
struct edge
{
    
    
	int end,next,red;
}a[N<<1];
int color[N],first[N],n,m,s,ans=-1,tot1,tot2,tot,want;
inline void inc(int x,int y,int z)
{
    
    
	a[++s]=(edge){
    
    y,first[x],z},first[x]=s;
	a[++s]=(edge){
    
    x,first[y],z},first[y]=s;
}
inline int mymin(int x,int y){
    
    return x<y?x:y;}
void dfs(int k)
{
    
    
	if(color[k]) tot1++;else tot2++;
	int i,j;
	for(i=first[k];i;i=a[i].next)
	{
    
    
		j=color[k]^want^a[i].red;
		if(color[a[i].end]<0)
		{
    
    
			color[a[i].end]=j;
			dfs(a[i].end);
			if(tot1<0) return;
		}
		else if(color[a[i].end]!=j){
    
    tot1=-1;return;}
	}
}
int main()
{
    
    
	int i,j,x,y;char ch;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) scanf("%d%d %c",&x,&y,&ch),inc(x,y,ch=='R');
	memset(color,-1,sizeof(color));
	for(i=1;i<=n;i++)
	{
    
    
		if(color[i]<0)
		{
    
    
			tot1=tot2=0;
			color[i]=1,dfs(i);
			if(tot1<0){
    
    tot=-1;break;}
			tot+=mymin(tot1,tot2);
		}
	}
	if(tot>=0) ans=tot;
	want=1,tot=0,memset(color,-1,sizeof(color));
	for(i=1;i<=n;i++)
	{
    
    
		if(color[i]<0)
		{
    
    
			tot1=tot2=0;
			color[i]=1,dfs(i);
			if(tot1<0){
    
    tot=-1;break;}
			tot+=mymin(tot1,tot2);
		}
	}
	if(tot>=0) ans=tot;
	printf("%d\n",ans);
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define N 100005
#define ll long long
char s[N];
int main()
{
    
    
	ll n,m,ans=0,i,j;
	scanf("%lld%lld %s",&n,&m,s+1);
	for(i=1;i<=n;i++) if(s[i]!=s[i-1]) ans+=n*(m-1);
	for(i=2,j=1;i<=n;i++)
	{
    
    
		if(j==1){
    
    if(s[i]!=s[i-1]) j++;}
		else
		{
    
    
			if(s[i]==s[i-2]) j++;
			else
			{
    
    
				ans-=(j-1)*j>>1;
				if(s[i]!=s[i-1]) j=2;
				else j=1;
			}
		}
	}
	ans-=(j-1)*j>>1;
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/88807527
今日推荐