2018.09.16(八校联考)

T1

考试时用了个神学做法水了85分,um其实和标答也就一个vecto/set的区别,数据可能是脚造的8

先预处理翻转前的固定点做前缀和,然后枚举对称轴,由内向外进行更新

然后就是,set的优先级和priority_queue相反的,然后重载运算符的时候不用反着来

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <set>
#define maxn 1000010
using namespace std;

int n,ans,a[maxn],sum[maxn];

int read()
{
	int xx=0,kk=1;char ch=' ';
	while(!isdigit(ch)){ch=getchar();if(ch=='-')kk=-1;}
	while(isdigit(ch)){xx=xx*10+ch-'0';ch=getchar();}
	return kk*xx;
}

struct node
{
	int i,ai;
	node(int i,int ai):i(i),ai(ai){};
	bool operator <(const node&a)const
	{
		return max(i,ai)<max(a.i,a.ai);
	}
};
multiset<node> v[maxn<<1];

int main()
{
	freopen("rotate.in","r",stdin);
	freopen("rotate.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i)
		a[i]=read(),v[a[i]+i].insert((node(i,a[i])));
	for(int i=1;i<=n;++i)
	    sum[i]=sum[i-1]+(a[i]==i);
	for(int i=1;i<=2*n;++i)
	{
		int tmp=0;
		while(v[i].size())
		{
			tmp++;
			node now=*v[i].begin();
			v[i].erase(v[i].begin());
			int maxi=max(now.i,now.ai);
			int mini=min(now.i,now.ai);
			ans=max(ans,sum[mini-1]+tmp+sum[n]-sum[maxi]);
		}
	}
	printf("%d",ans);
	return 0;
}
/*
12
10 9 8 4 6 5 7 3 2 1 12 11
*/

 

T2

比较有意思的最短路问题,考试的时候太sb了,没有考虑到周围都没有墙的情况,直接bfs居然还得了25...

考虑四周没有墙的情况其实就是往这个点上下左右的格子连长1的边,然后上下左右的墙连一条长dis+1的边,其中dis就等于这个格子到其上下左右的墙的最短距离

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <queue>
#define inf 1e9
#define maxn 520
#define maxm 250100
using namespace std;

char ch[maxn]; 
int n,m,num,s,t;
bool vis[maxm],obs[maxm];
int l[maxm],r[maxm],u[maxm],d[maxm],dis[maxm],fir[maxm];

struct qwq
{
	int nxt,to,val;
}e[maxm<<3];

struct qvq
{
	int u,d;
	bool operator <(const qvq&a)const
	{
		return d>a.d;
	}
};
priority_queue<qvq> q;

int getnum(int i,int j)
{
	return (i-1)*m+j;
}

void addedge(int u,int v,int w)
{
	e[++num].to=v;
	e[num].val=w;
	e[num].nxt=fir[u];
	fir[u]=num;
}

void dijkstra(int s)
{
	for(int i=1;i<=n*m;++i) dis[i]=inf;
	dis[s]=0,q.push((qvq){s,dis[s]});
	while(!q.empty())
	{
		qvq sx=q.top();q.pop();
		int u=sx.u,d=sx.d;
		if(dis[u]!=d) continue;
		for(int i=fir[u];i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(dis[u]+e[i].val<dis[v])
			{
				dis[v]=dis[u]+e[i].val;
				q.push((qvq){v,dis[v]});
			}
		}
    }
	
}

int main()
{
	freopen("cell.in","r",stdin);
	freopen("cell.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	{
		scanf("%s",ch+1);
		for(int j=1;j<=m;++j)
		{
			if(ch[j]=='#') obs[getnum(i,j)]=true;
			if(ch[j]=='C') s=getnum(i,j);
			if(ch[j]=='F') t=getnum(i,j);
		}
	}
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	{
		l[getnum(i,j)]=r[getnum(i,j)]=j;
		u[getnum(i,j)]=d[getnum(i,j)]=i;
	} 
	for(int i=2;i<=n;++i)
    for(int j=1;j<=m;++j)
	    if(!obs[getnum(i-1,j)]) u[getnum(i,j)]=u[getnum(i-1,j)];
	for(int i=n-1;i>=1;--i)
	for(int j=1;j<=m;++j)
	    if(!obs[getnum(i+1,j)]) d[getnum(i,j)]=d[getnum(i+1,j)];
	for(int i=1;i<=n;++i)
	for(int j=2;j<=m;++j)
	    if(!obs[getnum(i,j-1)]) l[getnum(i,j)]=l[getnum(i,j-1)];
	for(int i=1;i<=n;++i)
	for(int j=m-1;j>=1;--j)
	    if(!obs[getnum(i,j+1)]) r[getnum(i,j)]=r[getnum(i,j+1)];;
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	{
		if(obs[getnum(i,j)]) continue;
		if(i>1&&!obs[getnum(i-1,j)])addedge(getnum(i,j),getnum(i-1,j),1);
		if(i<n&&!obs[getnum(i+1,j)])addedge(getnum(i,j),getnum(i+1,j),1);
		if(j>1&&!obs[getnum(i,j-1)])addedge(getnum(i,j),getnum(i,j-1),1);
		if(j<m&&!obs[getnum(i,j+1)])addedge(getnum(i,j),getnum(i,j+1),1);
		int dis=min(min(j-l[getnum(i,j)],r[getnum(i,j)]-j),min(i-u[getnum(i,j)],d[getnum(i,j)]-i));
		addedge(getnum(i,j),getnum(i,l[getnum(i,j)]),dis+1);
		addedge(getnum(i,j),getnum(i,r[getnum(i,j)]),dis+1);
		addedge(getnum(i,j),getnum(u[getnum(i,j)],j),dis+1);
		addedge(getnum(i,j),getnum(d[getnum(i,j)],j),dis+1);
	}
	dijkstra(s);
	if(dis[t]==inf) puts("no");
	else printf("%d",dis[t]);
	return 0;
}
/*
6 8
########
#.##..F#
#C.##..#
#..#...#
#.....##
########
*/

 

T3

大概就是枚举最高点,三分高度,然后用树状数组来维护前后贡献

辣鸡南瓜码力不足

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值