1. 程式人生 > 實用技巧 >「考試」大假期集訓模擬15

「考試」大假期集訓模擬15

反思

  • 做過的題一定要看,寫的部落格一定要看
  • 資料範圍一定得注意,尤其是有時候他考試中途更新……
  • 見題還是一定要儘量寫點東西出來……

題目簡述

T1 貓和狗

太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了太丟人了
還認認真真寫的筆記走的思路結果考場就這樣寫掛成5分了
不說了,題解之前寫過,總之丟死人了

T2 旋轉子段

似乎考場出了正解還是挺自豪的(然而這也改變不了你T1的5分
以後一定要檢查資料範圍啊啊啊啊啊啊啊啊啊啊
(第二天就再犯了。
咳咳。廢話說多了。
這道題需要求旋轉後固定點的最大值,因為只用做一次旋轉,我們可以考慮每個點成為固定點需要怎麼轉
旋轉在這道題裡有兩個要素:中心,半徑
所以,對於每一個點,我們可以求出他成為固定點需要的旋轉中心和半徑,對於旋轉中心相同的點,他們是可以一起轉的,這個時候我們需要考慮旋轉半徑
因為每次旋轉會影響到被旋轉區間內所有的點,如果這個區間裡之前就有固定點,經過一次旋轉後他就不是固定點了
因此,我們可以用字首和處理一個區間內固定點的個數,在判斷時,用原來共有的固定點個數加上這次旋轉增加的固定點個數,再減去旋轉區間內原有的固定點個數,就是旋轉後的固定點個數。
列舉每一個旋轉中心和旋轉半徑,更新答案即可。
細節:旋轉中心可能是兩數中間,可以用類似\(manacher\)

的在中間插“板”解決
另外,\(vector\)真真真真好用qaq
code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define N 500005

ll n;
ll a[N];
ll pre[N*2];

/*
struct node
{
	ll ct,r;
}g[N<<1];
*/
ll c,r;
vector<ll> g[N*2];

ll ans=0;
ll t;

int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		t=i*2;
		pre[t-2]=pre[t-3];
		if(a[i]==i)pre[t-1]=pre[t-2]+1;
		else pre[t-1]=pre[t-2];
	}
	ll all=pre[n*2-1];
	//for(int i=1;i<=n*2-1;i++)cout<<pre[i]<<' ';cout<<endl;
	for(int i=1;i<=n;i++)
	{
		c=i+a[i]-1;
		//c=(i*2-1+a[i]*2-1)/2;
		r=abs(c-a[i]*2+1);
		//cout<<a[i]<<' '<<c<<' '<<r<<endl;
		g[c].push_back(r);
	}
	for(int i=1;i<=n*2-1;i++)
	{
		ll sz=g[i].size();
		if(!sz)continue;
		sort(g[i].begin(),g[i].end());
		for(int j=0;j<sz;j++)
		{
			//cout<<i<<' '<<j+1<<' '<<g[i][j]<<' '<<(i-g[i][j]+1)/2<<' '<<(i+g[i][j]+1)/2<<' '<<pre[i+g[i][j]]-pre[i-g[i][j]-1]<<endl;
			ans=max(ans,(ll)(all+j+1-pre[i+g[i][j]]+pre[i-g[i][j]-1]));
		}
	}
	printf("%lld",ans);
	return 0;
}

T3 走格子

考場上並沒有思路,怕不是對搜尋題有種天然的畏懼吧……

傳送門的本質就是到四個牆的距離等於到四個牆距離取min
——yspm

我們可以直接暴力預處理出每個非牆位置到上下左右牆的距離,然後相鄰格子連邊,權值為1,每個位置向上下左右牆前的位置連邊,權值為距離的min
然後在建好的圖上跑一個最短路就行了
\(spfa\)怎麼又忘了……

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define N 505
#define E 2000005
#define inf 10000000000000000
#define pll pair<ll,ll>
#define pq priority_queue
#define mp make_pair

const ll dx[4]={0,0,1,-1};
const ll dy[4]={1,-1,0,0};

struct edge
{
	ll u,v,w;
}e[E];
ll head[E],next[E],tot=0;
void add(ll a,ll b,ll c)
{
	++tot;
	e[tot].u=a;
	e[tot].v=b;
	e[tot].w=c;
	next[tot]=head[a];
	head[a]=tot;
}

ll n,m;
char ch[N][N];
ll ma[N][N];
ll S,T;
pq<pll > Q;

ll u[N][N],d[N][N],l[N][N],r[N][N];
ll ud[N][N],dd[N][N],ld[N][N],rd[N][N];
ll ds[N][N];

inline ll get(ll x,ll y)
{
	return x*(m-1)+y;
}
/*
void ins(ll x,ll y,ll w)
{
	if(ma[x][y]&&!ds[x][y])
	{
		ds[x][y]=w;
		Q.push(mp(x,y));
	}
}

void bfs()
{
	pll tmp;
	while(!Q.empty())
	{
		tmp=Q.top();
		Q.pop();
		ll x=tmp.first,y=tmp.second;
		for(int i=0;i<4;i++)
		{
			ins(x+dx[i],y+dy[i],ds[x][y]+1);
		}
	}
}*/

void pp()
{
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(!ma[i-1][j])u[i][j]=get(i,j);
		else u[i][j]=u[i-1][j];
		if(!ma[i][j-1])l[i][j]=get(i,j);
		else l[i][j]=l[i][j-1];
	}
	for(int i=n;i>=1;i--)for(int j=m;j>=1;j--)
	{
		if(!ma[i+1][j])d[i][j]=get(i,j);
		else d[i][j]=d[i+1][j];
		if(!ma[i][j+1])r[i][j]=get(i,j);
		else r[i][j]=r[i][j+1];
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(ma[i][j])ud[i][j]=ud[i-1][j]+1,ld[i][j]=ld[i][j-1]+1;
		/*else u[i][j]=u[i-1][j];
		if(!ma[i][j-1])l[i][j]=get(i,j-1);
		else l[i][j]=l[i][j-1];*/
	}
	for(int i=n;i>=1;i--)for(int j=m;j>=1;j--)
	{
		if(ma[i][j])dd[i][j]=dd[i+1][j]+1,rd[i][j]=rd[i][j+1]+1;
		/*if(!ma[i+1][j])d[i][j]=get(i+1,j);
		else d[i][j]=d[i+1][j];
		if(!ma[i][j+1])r[i][j]=get(i,j+1);
		else r[i][j]=r[i][j+1];*/
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(ma[i][j])ds[i][j]=min(min(min(ud[i][j],dd[i][j]),ld[i][j]),rd[i][j]);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(!ma[i][j])continue;
		ll now=get(i,j);
		for(int k=0;k<4;k++)if(ma[i+dx[k]][j+dy[k]])add(now,get(i+dx[k],j+dy[k]),1);
		add(now,u[i][j],ds[i][j]);
		add(now,d[i][j],ds[i][j]);
		add(now,l[i][j],ds[i][j]);
		add(now,r[i][j],ds[i][j]);
	}
}

queue<ll> q;
ll dis[N*N],vis[N*N];
ll t;
void spfa(ll s)
{
	for(int i=1;i<=n*m;i++)dis[i]=inf;
	dis[s]=0;
	vis[s]=1;
	q.push(s);
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		vis[t]=0;
		for(int i=head[t];i;i=next[i])
		{
			ll v=e[i].v;
			if(dis[v]>dis[t]+e[i].w)
			{
				dis[v]=dis[t]+e[i].w;
				if(!vis[v])
				{
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}

int main()
{
	//freopen("owo.in","r",stdin);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",ch[i]+1);
	
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		if(ch[i][j]=='#')
		{
			ma[i][j]=0;
		//	Q.push(mp(i,j));
		}
		else ma[i][j]=1;
		if(ch[i][j]=='C')S=get(i,j);
		if(ch[i][j]=='F')T=get(i,j);
	}
	pp();
	//for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<ds[i][j]<<' ';cout<<endl;}
	spfa(S);
	if(dis[T]!=inf)printf("%lld\n",dis[T]);
	else puts("no");
	return 0;
}

T4 柱狀圖

QAQ
正解:三分
學長的部落格好久才懂的……(侵刪