A
B

NOIP 模拟赛 2

NOIP 模拟赛总结

NOIP 模拟赛 2

诶嘿嘿,我是 rnk1 欸

T1 数字(math)

简单签到题,发现位数限制根本没用。(直接加小数点即可)

然后不断贪心地取值。

设第一个较大值给了 \(a\)

剩余的较大值直接全给 \(b\)

最后上个高精乘就成功地 A 掉了这道题。

点击查看代码
#include <bits/stdc++.h>
#define Blue_Archive return 0
#define int long long  	
using namespace std;
constexpr int N = 1e4 + 3;
constexpr int INF = 0x3f3f3f3f;

int T;
int a;
int b;
int len;
int aa[N];
int bb[N];
int ans[N];
int cnt[N];

inline void GaoJingCheng()
{
	for(int i = 1;i <= a;i ++)
	{
		for(int j = 1;j <= b;j ++)
		{
			ans[i + j - 1] += aa[i] * bb[j];
		}
	}
	for(int i = 1;;i ++)
	{
		if(ans[i] > 9) 
		{
			ans[i + 1] += ans[i] / 10;
			ans[i] %= 10;
		}
		if(ans[i + 1] == 0)
		{
			len = i;
			break;
		}
	}
}

inline void work()
{
	memset(aa,0,sizeof(aa));
	memset(bb,0,sizeof(bb));
	memset(ans,0,sizeof(ans));
	memset(cnt,0,sizeof(cnt));
	cin >> a >> b;
	len = min(a,b);
	if(a > b) swap(a,b);
	bool op = 1; // 判断两个数是否有不同(钦定 a > b)
	for(int i = 1;i <= 9;i ++) cin >> cnt[i];
	for(int i = 9,now = 0,las = 0;i >= 1;i --)
	{
		if(!cnt[i]) continue;
		if(las)
		{
			if(las == 1) bb[now] = i;
			if(las == 2) aa[now] = i;
			las = 0;
			cnt[i] --;
		}
		if(cnt[i] >= (len - now) * 2 + (las != 0))
		{
			while(now != len)
			{
				aa[++ now] = i;
				bb[now] = i;
				cnt[i] -= 2;
			}
			break;
		}
		if(cnt[i] >= 2)
		{
			int tim = cnt[i] / 2;
			while(tim)
			{
				aa[++ now] = i;
				bb[now] = i;
				tim --;
			}
		}
		cnt[i] %= 2;
		if(cnt[i] != 0)
		{
			if(op)
			{
				aa[++ now] = i;
				las = 1;
				op = 0;
			}
			else
			{
				bb[++ now] = i;
				las = 2;
			} 
			cnt[i] --;
		}
	}
	for(int i = 9,now = len;i >= 1;i --)
	{
		if(!cnt[i]) continue;
		while(cnt[i]) bb[++ now] = i,cnt[i] --;
	}
	for(int i = 1;i <= a / 2;i ++) swap(aa[i],aa[a - i + 1]);
	for(int i = 1;i <= b / 2;i ++) swap(bb[i],bb[b - i + 1]);
	len = 0;
	GaoJingCheng();
	for(int i = len;i;i --) cout << ans[i];
	cout << '\n';
}

signed main()
{
	freopen("math.in","r",stdin);freopen("math.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> T;
	while(T --) work();
	Blue_Archive;
}

T2 游戏(game)

发现是简单贪心,可以直接拆环扩成二倍的链。

设该点左右两端各 \({n / 2}\) 区间的和为 \(w\)

答案即是 \(\max_{i = 1}^{n} min_{j = i}^{i + n - 1}w_j\)

直接简单线段树维护。

点击查看代码
#include <bits/stdc++.h>
#define Blue_Archive return 0
#define lid (id << 1)
#define rid (id << 1 | 1)
using namespace std;
constexpr int N = 1e6 + 3;
constexpr int INF = 2e9;

int n;
int ans;
int a[N];
int b[N];
int sum[N];
int tr[N << 2];

inline void build(int id,int l,int r)
{
	if(l == r) return void(tr[id] = b[l]);
	int mid = (l + r) >> 1;
	build(lid,l,mid);
	build(rid,mid + 1,r);
	tr[id] = min(tr[lid],tr[rid]);
}

inline int query(int id,int l,int r,int L,int R)
{
	if(L > R || L > r || l > R) return INF;
	if(L <= l && r <= R) return tr[id];
	int mid = (l + r) >> 1;
	return min(query(lid,l,mid,L,R),query(rid,mid + 1,r,L,R));
}

signed main()
{
	freopen("game.in","r",stdin);freopen("game.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n;
	int len = (n + 1) / 2;
	for(int i = 1;i <= n;i ++)
	{
		cin >> a[i];
		a[i + n] = a[i];
	}
	for(int i = 1;i <= (n << 1);i ++) sum[i] = sum[i - 1] + a[i];
	for(int i = 1;i + len - 1 <= n * 2;i ++) b[i] = sum[i + len - 1] - sum[i - 1];
	for(int i = n * 2 - len + 2;i <= 2 * n;i ++) b[i] = INF;
	build(1,1,n << 1);
	ans = 0;
	for(int i = len,res;i <= 2 * n - len + 1;i ++)
	{
		res = query(1,1,n << 1,i - len + 1,i);
		ans = max(ans,res == INF ? 0 : res);
	}
	cout << ans << '\n';
	Blue_Archive;
}

T3:海报(posters)

卡时救了我qwq。

爆搜 + 剪枝。

发现如果有两个或更多个放在对角线(或角落里)肯定不劣。

剩下的直接爆搜即可。

注意剪枝:如果这个点已经被覆盖了,那么直接跳过,跑得飞快qwq。

点击查看代码
#include <bits/stdc++.h>
#define Blue_Archive return 0
#define int long long
#define lid (id << 1)
#define rid (id << 1 | 1)
using namespace std;
constexpr int N = 1e2 + 3;
constexpr int INF = 2e9;

int n;
int m;
int K;
int ans;

bool vis[N][N];

pair<int,int> pos[8];

struct miku
{
	int l,r;
}op[N];

inline void check()
{
	int res = 0;
	for(int k = 1,upl,upr;k <= K;k ++)
	{
		if(op[k].l + pos[k].first - 1 < n) upl = op[k].l + pos[k].first - 1;
		else upl = n;
		if(op[k].r + pos[k].second - 1 < m) upr = op[k].r + pos[k].second - 1;
		else upr = m;
		for(int i = pos[k].first;i <= upl;i ++)
		{
			for(int j = pos[k].second;j <= upr;j ++)
			{
				vis[i][j] = 1;
			}
		}
	}
	for(int i = 1;i <= n;i ++)	
	{
		for(int j = 1;j <= m;j ++)
		{
			if(vis[i][j])
			{
				res ++;
				vis[i][j] = 0;
			} 
		}
	}
	ans = max(ans,res);
	if(clock() > 950000) 
	{
		cout << ans << '\n';
		exit(0);
	}
}

inline void dfs(int x,int res)
{
	if(x + K - res > 6) return;
	if(x == 6)
	{
		if(res != K) return;
		check();
		return;
	}
	dfs(x + 1,res);
	for(int i = 1;i <= K;i ++)
	{
		if(pos[i].first && pos[i].second) continue;
		if(x == 1) pos[i] = {1,1},dfs(x + 1,res + 1),pos[i] = {0,0};
		if(x == 2) pos[i] = {1,m - op[i].r + 1},dfs(x + 1,res + 1),pos[i] = {0,0};
		if(x == 3) pos[i] = {n - op[i].l + 1,1},dfs(x + 1,res + 1),pos[i] = {0,0};
		if(x == 4) pos[i] = {n - op[i].l + 1,m - op[i].r + 1},dfs(x + 1,res + 1),pos[i] = {0,0};
		if(x == 5)
		{
			for(int j = 1;j + op[i].l <= n;j ++)
			{
				for(int k = 1;k + op[i].r <= m;k ++)
				{
					pos[i] = {j,k};
					dfs(x + 1,res + 1);
					pos[i] = {0,0};
				}
			}
		}
	}
}

signed main()
{
	freopen("posters.in","r",stdin);freopen("posters.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n >> m >> K;
	for(int i = 1;i <= K;i ++) cin >> op[i].l;
	for(int i = 1;i <= K;i ++) cin >> op[i].r;
	if(K == 1)
	{
		ans = min(n,op[1].l) * min(m,op[1].r);
		cout << ans << '\n';
		exit(0);
	}
	if(K == 2)
	{
		int upl,upr;
		upl = min(op[1].l,n);
		upr = min(op[1].r,m);
		for(int i = 1;i <= upl;i ++)
		{
			for(int j = 1;j <= upr;j ++)
			{
				vis[i][j] = 1;
			}
		}
		upl = max(n - op[2].l + 1,1ll);
		upr = max(m - op[2].r + 1,1ll);
		for(int i = upl;i <= n;i ++)
		{
			for(int j = upr;j <= m;j ++)
			{
				vis[i][j] = 1;
			}
		}
		for(int i = 1;i <= n;i ++)
		{
			for(int j = 1;j <= m;j ++)
			{
				if(vis[i][j]) ans ++;
			}
		}
		cout << ans << '\n';
		exit(0);
	}
	if(K >= 3)
	{
		dfs(0,0);
		cout << ans << '\n';
		exit(0);
	}
	Blue_Archive;
}

T4:环(ring)

根号分治,可惜场上没时间写完了。

直接对环的大小进行根号分治即可。

点击查看代码
#include <bits/stdc++.h>
#define Blue_Archive return 0
#define int long long
using namespace std;
constexpr int N = 1.5e5 + 3;
constexpr int M = 400;
constexpr int INF = 2e9;

int n;
int m;
int q;
int len;
int top;
int a[N];
int c[N];
int id[N];
int st[M];
int ed[M];
int laz[N];
int sum[N];
int siz[N];
int stk[N];
int sum2[N];

vector<int> f[N],sum1[N];

inline void update(int x)
{
	if(siz[x] > len) return void(laz[x] ++);
	for(int i = f[x].size() - 1;i >= 1;i--)
	{
		sum[id[f[x][i]]] = sum[id[f[x][i]]] - a[f[x][i]] + a[f[x][i - 1]];
		sum[id[f[x][i - 1]]] = sum[id[f[x][i - 1]]] + a[f[x][i]] - a[f[x][i - 1]];
		swap(a[f[x][i]],a[f[x][i - 1]]);
	}
}

inline int query(int l,int r)
{
	int res = 0;
	if(id[l] == id[r])
	{
		for(int i = l;i <= r;i ++)
		{
			if(siz[c[i]] > len) continue;
			res += a[i];
		}
	}
	else 
	{
		for(int i = l;i <= ed[id[l]];i ++) 
		{
			if(siz[c[i]] > len) continue;
			res += a[i];
		}
		for(int i = st[id[r]];i <= r;i ++) 
		{
			if(siz[c[i]] > len) continue;
			res += a[i];
		}
		for(int i = id[l] + 1;i < id[r];i ++) res += sum[i];
	}
	for(int i = 1,ql,qr,ansl,ansr;i <= top;i ++)
	{
		ql = lower_bound(f[stk[i]].begin(),f[stk[i]].end(),l) - f[stk[i]].begin();
		qr = upper_bound(f[stk[i]].begin(),f[stk[i]].end(),r) - f[stk[i]].begin() - 1;
		if(ql > qr) continue;
		ansl = ((ql - laz[stk[i]]) % siz[stk[i]] + siz[stk[i]]) % siz[stk[i]];
		ansr = ((qr - laz[stk[i]]) % siz[stk[i]] + siz[stk[i]]) % siz[stk[i]];
		if(ansl <= ansr)
		{
			if(ansl == 0) res += sum1[stk[i]][ansr];
			else res += sum1[stk[i]][ansr] - sum1[stk[i]][ansl - 1];
		}
		else res += sum1[stk[i]][ansr] + sum1[stk[i]][siz[stk[i]] - 1] - sum1[stk[i]][ansl - 1];
	}
	return res;
}

signed main()
{
	freopen("ring.in","r",stdin);freopen("ring.out","w",stdout);
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n >> m >> q;
	len = sqrt(n);
	for(int i = 1;i <= n;i ++) cin >> c[i],siz[c[i]] ++;
	for(int i = 1;i <= m;i ++) f[i].reserve(siz[i] + 1),sum1[i].reserve(siz[i] + 1);
	for(int i = 1;i <= n;i ++) f[c[i]].emplace_back(i);
	for(int i = 1;i <= n;i ++)
	{
		id[i] = (i - 1) / len + 1; 
		cin >> a[i];
		if(siz[c[i]] <= len) sum[id[i]] += a[i];
		if(!st[id[i]]) st[id[i]] = i;
		ed[id[i]] = i;
	} 
	for(int i = 1;i <= m;i ++)
	{
		if(siz[i] <= len) continue;
		stk[++ top] = i;
		for(int j = 1;j <= siz[i];j ++)
		{
			sum2[j] = sum2[j - 1] + a[f[i][j - 1]];
			sum1[i].emplace_back(sum2[j]);
		} 
	} 
	for(int i = 1,op,l,r,x;i <= q;i ++)
	{
		cin >> op;
		if(op == 1)
		{
			cin >> l >> r;
			cout << query(l,r) << '\n';
		}
		else 
		{
			cin >> x;
			update(x);
		}
	}
	Blue_Archive;
}
posted @ 2025-11-14 08:27  MyShiroko  阅读(20)  评论(1)    收藏  举报