码迷,mamicode.com
首页 > 其他好文 > 详细

20170116小测233

时间:2017-01-16 21:09:20      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:break   style   scanf   修改   ring   区间   没有   完全   line   

更正:pdfT1(mex)中的前两个“她”误打成了“他”...

T1:mex

分析:

我们可以得到mex函数一个很有用的性质:左端点相同,右端点递增,mex递增...

所以我们可以O(n)滴求出mex(1,i)...然后我们维护左端点的位置,从1到n,每次左端点向右移动一位,就可以更新i+1到下一次a[i]出现的位置的mex函数,这样暴力修改是O(n^2)的,可以拿到60分...

如果要拿满分显然可以用线段树维护区间修改区间求和...

还有另一种代码短常数小的方法---递推...

记f[i]代表Σ(1<=x<=i)mex[x,i]我们可以通过上面那种性质得到f[i]是递增的...

所以可以根据f[i]间接推出f[i+1],记第i个数为sa[i],显然只用考虑大于等于sa[i]的数j对f[i]=f[i-1]+?的影响,。如果j出现在1~i-1区间中,比较j最晚出现的位置与覆盖完全的1~j-1的最小位置的较小位置k,那么区间j的前一次出现的位置到k位置这个区间内所有点到i位置的值都+1.

代码:

(递推)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
#define int long long
using namespace std;
//mei yan ru chu,sui yue ru gu

const int maxn=500000+5;

int n,ans,a[maxn],p[maxn],mp[maxn],mex[maxn],nxt[maxn],vis[maxn],last[maxn];

inline void solve1(void){
	for(int i=1;i<n;i++){
		for(int j=i+1;j<nxt[i];j++)
			if(mex[j]>a[i])
				mex[j]=a[i];
		for(int j=i+1;j<=n;j++)
			ans+=mex[j];
	}
	printf("%lld\n",ans);
}

inline void solve2(void){
	int now=0,pre;ans=0;
	for(int i=1;i<=n;i++){
		pre=p[a[i]];p[a[i]]=i;
		for(int j=a[i];j<=n;j++){
			if(j)
				mp[j]=min(mp[j-1],p[j]);
			else
				mp[j]=p[j];
			if(mp[j]>pre)
				now+=mp[j]-pre;
			else
				break;
		}
		ans+=now;
	}
	printf("%lld\n",ans);
}

signed main(void){
//	freopen("mex.in","r",stdin);
//	freopen("mex.out","w",stdout);
	scanf("%lld",&n);ans=0;
	for(int i=1;i<=n;i++)
		nxt[i]=n+1;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		if(a[i]>n)
			a[i]=n;
		if(last[a[i]])
			nxt[last[a[i]]]=i,last[a[i]]=i;
		else
			last[a[i]]=i;
	}int lala=0;
	for(int i=1;i<=n;i++){
		if(a[i]==lala){
			vis[a[i]]=1;
			while(vis[lala])
				lala++;
		}
		else
			vis[a[i]]=1;
		mex[i]=lala;ans+=lala;
	}
	if(n<=1000)
		solve1();
	else
		solve2();
	fclose(stdin);fclose(stdout);
	return 0;
}//Cap ou pas cap. Pas cap.

T2:game

分析:

有一些点,黑白染色,大概是二分图吧...

我们首先离散化坐标,对于每一个点,我们把行和列连边,然后每一次寻找一条交错路,黑白染色,然后再从这个点出发寻找交错路,相邻两次的交错路第一次的染色不同...

这样构造出来的答案差值最多是1...(因为我们是黑白交错染色...所以差值最大只可能是1)

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
//by NeighThorn
using namespace std;
//dan shi xiang si mo xiang fu,mu dan ting shang san sheng lu

const int maxn=600000+5;

int n,cntx,cnty,tot,hd[maxn],to[maxn],id[maxn],nxt[maxn],pos[maxn][2];

char ans[maxn];

map<int,int> mpx,mpy;

inline void add(int s,int x,int y){
	to[tot]=y;id[tot]=s;nxt[tot]=hd[x];hd[x]=tot++;
}

inline void dfs(int x,int co){
	for(int i=hd[x];i!=-1;hd[x]=i=nxt[i])
		if(ans[id[i]]==0){
			ans[id[i]]=co+‘0‘,dfs(to[i],co^1);return;
		}
}

signed main(void){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d",&n);cntx=cnty=0;tot=0;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&pos[i][0],&pos[i][1]);
		if(mpx.find(pos[i][0])==mpx.end())
			mpx[pos[i][0]]=++cntx;
		if(mpy.find(pos[i][1])==mpy.end())
			mpy[pos[i][1]]=++cnty;
		pos[i][0]=mpx[pos[i][0]],pos[i][1]=mpy[pos[i][1]];
	}
	memset(hd,-1,sizeof(hd));
	for(int i=1;i<=n;i++)
		add(i,pos[i][0],pos[i][1]+cntx),add(i,pos[i][1]+cntx,pos[i][0]);
	for(int i=1;i<=cntx;i++){
		int now=1;
		for(int j=hd[i];j!=-1;hd[i]=j=nxt[j])
			if(ans[id[j]]==0)
				ans[id[j]]=now+‘0‘,dfs(to[j],now^1),now^=1;
	}
	for(int i=1;i<=n;i++)
		printf("%c",ans[i]);puts("");
	fclose(stdin);fclose(stdout);
	return 0;
}//Cap ou pas cap. Pas cap.

T3:another

分析:

一看数据范围好大哦...其实没有什么用只要看是不是零就好...

把01矩阵看成邻接矩阵,然后A^k就是从i到j走k步的路径数,又因为至少有一个自环,所以如果整张图是一个强连通分量就是合法的...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
//liang chen mei jing nai he tian,shang xin le shi shui jia yuan

const int maxn=1000+5;

int C,n,cas,cnt,tim,tail,flag,hd[maxn],to[maxn*maxn],mp[maxn],nxt[maxn*maxn],dfn[maxn],low[maxn],stk[maxn],instk[maxn];

inline int read(void){
	char ch=getchar();int x=0;
	while(!(ch>=‘0‘&&ch<=‘9‘))
		ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘)
		x=x*10+ch-‘0‘,ch=getchar();
	return x;
}

inline void add(int x,int y){
	to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}

inline void tarjan(int x){
	dfn[x]=low[x]=++tim;stk[++tail]=x;instk[x]=1;
	for(int i=hd[x];i!=-1;i=nxt[i]){
		if(!dfn[to[i]])
			tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
		else if(instk[to[i]])
			low[x]=min(dfn[to[i]],low[x]);
	}
	if(low[x]==dfn[x]){
		int tmp;C++;
		do{
			tmp=stk[tail--];mp[tmp]=C;instk[tmp]=0;
		}while(tmp!=x);
	}
}

signed main(void){
	freopen("another.in","r",stdin);
	freopen("another.out","w",stdout);
	cas=read();
	while(cas--){
		flag=1;C=cnt=tim=tail=0;
		memset(mp,0,sizeof(mp));
		memset(hd,-1,sizeof(hd));
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		memset(instk,0,sizeof(instk));
		n=read();
		for(int i=1;i<=n;i++)
			for(int j=1,x;j<=n;j++){
				x=read();
				if(x)
					add(i,j);
			}
		tarjan(1);
		for(int i=1;i<=n&&flag;i++)
			if(mp[i]!=mp[1])
				flag=0;
		puts(flag==0?"NO":"YES");
	}
	fclose(stdin);fclose(stdout);
	return 0;
}//Cap ou pas cap. Pas cap.

  


By NeighThorn

20170116小测233

标签:break   style   scanf   修改   ring   区间   没有   完全   line   

原文地址:http://www.cnblogs.com/neighthorn/p/6290229.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!