A
B

NOIP 模拟赛 6 & 多校 1

NOIP 模拟赛总结

NOIP 模拟赛 6 & 多校 1

挂分啦

T1 汉谟拉比(crazy)

不简单签到题,但是放过了 \(O(n m ^ 2)\)

正解是发现要进行 \(n\) 次卷积。

所以考虑广义快速幂即可。

点击查看代码
#include <bits/stdc++.h>
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
constexpr int N = 5e3 + 3;
constexpr int INF = 1e9;

int n;
int m;
int mx;
int ans;
int a[N];
int w[N];
int dp[N][N];

inline int read() // 不读负数的普通快读
{
	int k = 0,f = 1;
	int c = getchar_unlocked();
	while(c < '0' || c > '9') c = getchar_unlocked();
	while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + (c ^ 48),c = getchar_unlocked();
	return k * f;
}

inline void write(int x) // 普通快写
{
	if(x < 0) putchar_unlocked('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}

inline int max(int a,int b){return a > b ? a : b;}
inline int min(int a,int b){return a < b ? a : b;}

signed main()
{
	freopen("crazy.in","r",stdin);freopen("crazy.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("ans.out","w",stdout);
	n = read();
	m = read();
	for(int i = 1;i <= n;i ++)
	{
		a[i] = read();
		w[a[i]] ++;
		mx = max(mx,a[i]);
	} 
	mx = min(mx,m);
	for(int i = 1;i <= mx;i ++) w[i] += w[i - 1];
	if(1ll * n * mx * m <= 1e9)
	{
		for(int i = 1;i <= n;i ++)
		{
			for(int k = 0;k <= mx;k ++)
			{
				for(int j = k;j <= m;j ++)
				{
					if(dp[i][j] < dp[i - 1][j - k] + w[k]) dp[i][j] = dp[i - 1][j - k] + w[k];
				}
			}
		}
	}
	else 
	{
		for(int i = 1;i <= n;i ++)
		{
			for(int k = 0;k <= min(800,mx);k ++)
			{
				for(int j = k;j <= m;j ++)
				{
					if(dp[i][j] < dp[i - 1][j - k] + w[k]) dp[i][j] = dp[i - 1][j - k] + w[k];
				}
			}
			for(int k = max(mx - 800,0);k <= mx;k ++)
			{
				for(int j = k;j <= m;j ++)
				{
					if(dp[i][j] < dp[i - 1][j - k] + w[k]) dp[i][j] = dp[i - 1][j - k] + w[k];
				}
			}
		}
	}
	write(n * n - dp[n][m]),ent;
	Blue_Archive;
}

T2 虫洞折跃(flip)

判无解死亡导致又挂 20 pts。

简单 dp + 超级多判无解。

点击查看代码
#include <bits/stdc++.h>
#define int long long 
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
constexpr int N = 1e3 + 3;
constexpr int M = 1e6 + 3;
constexpr int INF = 1e9;

int T;
int n;
int m;
int ans;
int dis[N][N];

bool a[N][N];

inline int read() // 不读负数的普通快读
{
	int k = 0,f = 1;
	int c = getchar_unlocked();
	while(c < '0' || c > '9') c = getchar_unlocked();
	while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + (c ^ 48),c = getchar_unlocked();
	return k * f;
}

inline void write(int x) // 普通快写
{
	if(x < 0) putchar_unlocked('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}

inline int max(int a,int b){return a > b ? a : b;}
inline int min(int a,int b){return a < b ? a : b;}

inline void work()
{
	n = read();
	m = read();
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= m;j ++)
		{
			a[i][j] = read();
		}
	}
	if(n == 1 && m == 1 && a[1][1]) return void(puts("Impossible"));
	if(n == 1 && m == 2 && a[1][1] + a[1][2] == 1) return void(puts("Impossible"));
	if(n == 2 && m == 1 && a[1][1] + a[2][1] == 1) return void(puts("Impossible"));
	if(n == 1 && m == 4 && a[1][4] && !a[1][1] && !a[1][2] && !a[1][3]) return void(puts("2"));
	memset(dis,0x3f,sizeof(dis));
	dis[1][1] = a[1][1];
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= m;j ++)
		{
			if(a[i][j]) 
			{
				if(i < n) dis[i + 1][j] = min(dis[i + 1][j],dis[i][j]);
				if(j < m) dis[i][j + 1] = min(dis[i][j + 1],dis[i][j]);
			}
			else 
			{
				if(i < n && a[i + 1][j]) dis[i + 1][j] = min(dis[i + 1][j],dis[i][j] + 1);
				if(i < n && !a[i + 1][j]) dis[i + 1][j] = min(dis[i + 1][j],dis[i][j]);
				if(j < m && a[i][j + 1]) dis[i][j + 1] = min(dis[i][j + 1],dis[i][j] + 1);
				if(j < m && !a[i][j + 1]) dis[i][j + 1] = min(dis[i][j + 1],dis[i][j]);
			}
		}
	}
	if(dis[n][m] >= INF) puts("Impossible");
	else write(dis[n][m]),ent;
}

signed main()
{
	freopen("flip.in","r",stdin);freopen("flip.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	T = read();
	while(T --) work();
	Blue_Archive;
}

T3:深巢温泉(dnspring)

不会,咕咕。

T4:逃离冰场(skate)

神秘图论建模题。

发现每到相邻的一格需要 2 步,

每到最近的冰块的前一格需要一步。

然后直接连边跑最短路即可。

点击查看代码
#include <iostream>
#include <string.h>
#include <queue>
#define id(u,v) ((u - 1) * m + v)
#define add(u,v,c) to[++ tot] = v,w[tot] = c,nxt[tot ] = h[u],h[u] = tot
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
constexpr int N = 1e3 + 3;
constexpr int L = 1e6 + 3;
constexpr int M = 1e7 + 3;
constexpr int INF = 1e9;

int n;
int m;
int tot;
int ans;
int sx,sy;
int ex,ey;
int h[L];
int w[M];
int to[M];
int nxt[M];
int dis[L];

bool vis[M];
bool a[N][N];

inline int max(int a,int b){return a > b ? a : b;}
inline int min(int a,int b){return a < b ? a : b;}

priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;

inline void dijk(int s)
{
	memset(dis,0x3f,sizeof(dis));
	dis[s] = 0;
	q.push({0,s});
	while(!q.empty())
	{
		int u = q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = h[u];i;i = nxt[i])
		{
			if(dis[to[i]] > dis[u] + w[i])
			{
				dis[to[i]] = dis[u] + w[i];
				q.push({dis[to[i]],to[i]});
			}
		}
	}
}

signed main()
{
	freopen("skate.in","r",stdin);freopen("skate.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	char op;
	cin >> n >> m;
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= m;j ++)
		{
			cin >> op;
			if(op == '#') a[i][j] = 1;
		}
	}
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= m;j ++)
		{
			if(a[i][j]) continue;
			if(!a[i - 1][j]) add(id(i - 1,j),id(i,j),2);
			if(!a[i + 1][j]) add(id(i + 1,j),id(i,j),2);
			if(!a[i][j - 1]) add(id(i,j - 1),id(i,j),2);
			if(!a[i][j + 1]) add(id(i,j + 1),id(i,j),2);
		}
	}
	for(int i = 1,las = -1;i <= n;i ++)
	{
		for(int j = 2;j <= m;j ++)
		{
			if(a[i][j]) continue;
			if(a[i][j - 1]) las = j;
			else add(id(i,j),id(i,las),1);
		}
		for(int j = m - 1;j >= 1;j --)
		{
			if(a[i][j]) continue;
			if(a[i][j + 1]) las = j;
			else add(id(i,j),id(i,las),1);
		}
	}
	for(int i = 1,las = -1;i <= m;i ++)
	{
		for(int j = 2;j <= n;j ++)
		{
			if(a[j][i]) continue;
			if(a[j - 1][i]) las = j;
			else add(id(j,i),id(las,i),1);
		}
		for(int j = n - 1;j >= 1;j --)
		{
			if(a[j][i]) continue;
			if(a[j + 1][i]) las = j;
			else add(id(j,i),id(las,i),1);
		}
	}
	cin >> sx >> sy;
	cin >> ex >> ey;
	dijk(id(sx,sy));
	ans = (dis[id(ex,ey)] >= INF ? -1 : dis[id(ex,ey)]);
	cout << ans << '\n';
	Blue_Archive;
}
posted @ 2025-11-14 08:27  MyShiroko  阅读(11)  评论(0)    收藏  举报