NOIP模拟3

A. 三元

3L+11 内的数写出来,发现要最高位 0,1,2 都留 n 个,那么字典序的限制只对 2 有用,把前 n2 开头写出来
然后每次按位变成 x+1mod3

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int read(){
	int x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 200005;
int n, L;
struct tre{
	int a[18], num;
	void init(int x){
		int p = 0;
		while(x){
			a[p++] = x % 3;
			x /= 3;
		}
	}
	void print(){
		for(int i = L - 1; i >= 0; --i)printf("%d",a[i]);
		printf("\n");
	}
	void get_num(){
		int s = 1;num = 0;
		for(int i = 0; i < L; ++i){
			num += s * a[i];
			s *= 3;
		}
	}
	tre dec(){
		tre b;
		for(int i = L - 1; i >= 0; --i)b.a[i] = (a[i] + 4) % 3;
		return b;
	}
	friend bool operator < (const tre &x, const tre &y){
		return x.num < y.num;
	}
}a[maxn];

int main(){
	freopen("three.in","r",stdin);
	freopen("three.out","w",stdout);
	n = read(), L = read();
	int now = 1; 
	for(int i = 1; i < L; ++i)now = now * 3; now = now * 2;
	for(int i = 1; i <= n; ++i){a[i].init(now); ++now;}
	for(int i = 1; i <= n; ++i)a[i + n] = a[i].dec(), a[i + n + n] = a[i + n].dec();
	for(int i = 1; i <= n + n + n; ++i)a[i].get_num();
	sort(a + 1, a + n + n + n + 1);
	for(int i = 1; i <= n + n + n; ++i)a[i].print();
	return 0;
}

B. 鹅国

因为没有注意数据范围会炸longlong 寄掉

直接暴力,加上两个小剪枝,不知道复杂度对不对,感觉挺优的,不过更希望有人能够卡掉,或者严谨证明

正解从别人博客里翻吧

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

ll read(){
	ll x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}

const int maxn = 1005;
int n, k; ll p;
ll c[maxn], w[maxn];
unordered_map<ll ,ll>mp[1005], tmp[1005];
int cnt;
void Ckmx(ll &x, ll y){if(y > x)x = y;}
void Ckmi(ll &x, ll y){if(x == 0 || x > y)x = y;}
typedef pair<ll, ll> pll;
vector<ll>vec;
int main(){
	// freopen("goose.in","r",stdin);
	// freopen("goose.out","w",stdout);
	n = read(), k = read(), p = read();
	for(int i = 1; i <= n; ++i)c[i] = read(), w[i] = read();
	for(int i = n; i >= 1; --i){
		if(c[i] + (__int128)(k - 1) * c[1] > p)continue;
		mp[1][c[i]] = w[i];
		tmp[1][c[i]] = w[i];
		for(int j = 1; j < k; ++j){
			__int128 mx = p - (__int128)c[1] * (k - j), mi = p - (__int128)c[i] * (k - j);
			vec.clear();
			for(auto x : mp[j])if(x.first < mi || x.first > mx)vec.push_back(x.first);
			for(ll x : vec)mp[j].erase(x), tmp[j].erase(x);
			for(auto x : mp[j])if(p - x.first >= c[i])Ckmi(mp[j + 1][x.first + c[i]], x.second + w[i]);
			for(auto x : tmp[j])if(p - x.first >= c[i])Ckmx(tmp[j + 1][x.first + c[i]], x.second + w[i]);
		}
	}
	if(mp[k][p] == 0){
		printf("-1\n");
		return 0;
	}
	printf("%lld %lld\n",mp[k][p], tmp[k][p]);
	printf("%d\n",cnt);
	return 0;
}

C. 楼盘

NBDP

暂时弃

code

D. 矩形

容易计算 <=val 的矩形数量,于是可以二分,不知道赛时为啥RE

二分得到 L,R 的值以后,可以查询值介于 L,R 之间的矩形数量以及大小,因为只查询了有用的,所以总复杂度是 O(n+RL+1) 大概?

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
ll read(){
	ll x = 0; char c = getchar();
	while(!isdigit(c))c = getchar();
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return x;
}
const int maxn = 3000005;
ll n, h[maxn], L, R;
int l[maxn], r[maxn], sta[maxn], top;
ll calc(ll s, ll w){return s < 0 || w < 0 ? 0 : (s + w) * (s - w + 1) / 2;}
ll sum(int i, ll mx){return mx <= 0 ? 0 : calc(r[i] - l[i] + 1 ,  r[i] - l[i]  + 1 - min(mx, r[i] - l[i] + 1ll) + 1) - calc(i - l[i], i - l[i] - min(mx, i - l[i] + 0ll) + 1) - calc(r[i] - i, r[i] - i - min(mx, r[i] - i + 0ll) + 1);}

ll check(ll mid){
	ll ans = 0;
	for(int i = 1; i <= n; ++i)if(r[i] - l[i] + 1)ans += sum(i, mid / h[i]);
	return ans;
}
ll solve(ll q){
	ll ansl = 1, ansr = 3e14, ans = -1;
	while(ansl <= ansr){
		ll mid = (ansl + ansr) >> 1;
		if(check(mid) >= q)ansr = mid - 1, ans = mid;
		else ansl = mid + 1;
	}
	return ans;
}
vector<ll>ans;
void get(ll pl, ll pr){
	if(pl > pr)return;
	for(int i = 1; i <= n; ++i){
		for(ll len = (pl + h[i] - 1) / h[i]; len * h[i] <= pr && len <= r[i] - l[i] + 1; ++len){
			ll num = sum(i, len) - sum(i, len - 1);
			for(int p = 1; p <= num; ++p)ans.push_back(h[i] * len);
		}
	}
}
void sol(){
	for(int i = 1; i <= n; ++i){
		while(top && h[sta[top]] > h[i])--top;
		l[i] = sta[top] + 1; sta[++top] = i;
	}
	sta[top = 0]  = n + 1;
	for(int i = n; i >= 1; --i){
		while(top && h[sta[top]] >= h[i])--top;
		r[i] = sta[top] - 1; sta[++top] = i;
	}
	ll lval = solve(L), rval = solve(R);
	ll clval = check(lval);
	for(ll i = L; i <= clval && ans.size() < R - L + 1; ++i)ans.push_back(lval);
	get(lval + 1, rval - 1);
	while(ans.size() < R - L + 1)ans.push_back(rval);
	sort(ans.begin(), ans.end());
	for(ll x : ans)printf("%lld ",x);
}
int main(){
	freopen("rectangle.in","r",stdin);
	freopen("rectangle.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; ++i)h[i] = read();
	L = read(), R = read();
	sol();
	return 0;
}

posted @   Chen_jr  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示