2022NOIP A层联测13

A. QAQ

注意到状态数最多也就 nlogx 于是用 map 直接爆力转移即可

题解说状态数为 O(n) 级别,不会证

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

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int mod = 998244353;
int x, n, p;

unordered_map<int, int> mp, tmp;


void add(int &x, int y){x += y; x = x >= mod ? x - mod : x;}
int count(int x){
	int ans = 0;
	while(x && x % 2 == 0){
		x /= 2; ++ans;
	}
	return ans;
}
int main(){
	freopen("qaq.in","r",stdin);
	freopen("qaq.out","w",stdout);
	scanf("%d%d%d",&x,&n,&p);
	mp[x] = 1;
	for(int i = 1; i <= n; ++i){
		for(auto v : mp){
			add(tmp[v.first / 2], 1ll * v.second * p % mod);
			add(tmp[v.first + 1], 1ll * v.second * (mod + 1 - p) % mod);
		}
		mp = tmp; tmp.clear();
	}
	int ans = 0;
	for(auto v : mp)add(ans, 1ll * count(v.first) * v.second % mod);
	printf("%d\n",ans);
	return 0;
}

B. 游戏

交互题只是为了方便写 spj ?

用到哥德巴赫猜想

image

于是当 n 为偶数时, 如果 (n1) 是质数,那么 3 个因子

否则他一定能够写成两个质数 p1+p2 的形式,于是有 4 个因子

如果 n 为奇数,那么当 n2 为质数时,有 4 个因子

否则他可以写成 1+p1+p2, 有 5 个因子

上面的情况说明了答案的上界,取最小的答案还要与他本身因子个数取 min

注意到 n 比较小时候需要一些特判,于是我干脆留下了考场暴力,免去讨论

code
#include<bits/stdc++.h>
#include <map>
#include <utility>
#include"game.h"
using namespace std;
typedef long long ll;
const int maxn = 500000 + 55;
int prime[maxn], cnt, num[maxn], ci[maxn], cp[maxn];
bool flag[maxn];
int mi[maxn];
map<int, int>rm[maxn];

bool isprime(const ll n){
	if(n <= 0)return false;
	if(n == 1)return false;
	for(ll i = 2; i * i <= n ;i++)
		if(n % i == 0)return false;
	return true;
}
int d(const int n){
    if(n == 1)return 1;
    if(isprime(n))return 2;
    int res = 0;
    for(int i = 1;i * i <= n;i++)
        if(n % i == 0){
            res++;
            if(i * i != n)res++;
        }
    return res;
}
void pre(){
	ci[1] = num[1] = 1;
	for(int i = 2; i <= 300000; ++i){
		if(!flag[i])prime[++cnt] = i, ci[i] = 1, num[i] = 2;
		cp[i] = cnt;
		for(int j = 1; j <= cnt && prime[j] * i <= 300000; ++j){
			int k = i * prime[j];
			flag[k] = 1;
			if(i % prime[j] == 0){
				ci[k] = ci[i] + 1;
				num[k] = num[i] / (ci[i] + 1) * (ci[k] + 1);
				break;
			}
			ci[k] = 1; num[k] = num[i] * 2;
		}
	}
	rm[1][1] = 1; mi[1] = 1;
	for(int i = 2; i <= 100000; ++i){
		int now = i; mi[i] = num[i];
		for(int j = cp[i]; prime[j] >= i / 2; --j)if(mi[i] > mi[prime[j]] + mi[i - prime[j]]){
			mi[i] = mi[prime[j]] + mi[i - prime[j]];
			now = prime[j];
		}
		if(now != i){
			for(auto v : rm[now])rm[i][v.first] += v.second;
			now = i - now;
			for(auto v : rm[now])rm[i][v.first] += v.second;
		}else rm[now][now] = 1;
	}
}
bool fl;
pair<map<int, int>, map<int, int>> solve(int n) {
	if(!fl)pre(), fl = 1;
	map<int, int> fi, se;
	if(n <= 100000)fi = rm[n];
	else{
		if(isprime(n))fi[n] = 1;
		else{
			int mi = d(n);
			if(isprime(n - 1) && mi > 3){
				mi = 3;
				++fi[1];
				++fi[n - 1];
				goto X;
			}
			if((n & 1) == 0 && mi > 4){
				for(int j = 1; j <= cnt; ++j){
					int p = prime[j];
					if(isprime(n - p)){
						++fi[p];
						++fi[n - p];
						goto X;
					}
				}
			}
			if((n & 1)){
				if(isprime(n - 2) && mi > 4){
					++fi[n - 2]; ++fi[2];
					goto X;
				}
				if(mi > 5)
				for(int j = 1; j <= cnt; ++j){
					int p = prime[j];
					if(n - p - 1 <= 0)break;
					if(isprime(n - p - 1)){
						++fi[p];
						++fi[n - p - 1];
						++fi[1];
						goto X;
					}
				}
			}
			fi[n] = 1;
		}
	}
	X:;
	se[1] = n;
	return make_pair(fi, se);
}

C. QWQ

目前不理解,暂留

code

D. 修仙

套路题,跟种树一毛一样,因为之前某天拉着 Delov 打过一天可反悔贪心,今天捡了个板子题

bi=ai+ajmax(ai+ajx,0), 那么问题转化为选取 k 个不相邻的 bi 使得他们的权值和最大,于是就完全是种树了

如果你想看看自己对可反悔贪心的理解程度,可以看看这个题单

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 = 250005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n, x;
ll a[maxn], val[maxn];
typedef pair<ll, int> pli;
priority_queue<pli>q;
int l[maxn], r[maxn];
bool de[maxn];
void del(int x){
	r[l[l[x]]] = x;
	l[r[r[x]]] = x;
	val[x] = val[l[x]] + val[r[x]] - val[x];
	de[l[x]] = de[r[x]] = 1;
	l[x] = l[l[x]];
	r[x] = r[r[x]];
}

int main(){
	freopen("restart.in","r",stdin);
	freopen("restart.out","w",stdout);
	n = read(), x = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	for(int i = 1; i < n; ++i)val[i] = a[i] + a[i + 1] - max(a[i] + a[i + 1] - x, 0ll);
	for(int i = 1; i < n; ++i)l[i] = i - 1, r[i] = i + 1, q.push(pli(val[i], i));
	val[0] = -inf, val[n] = -inf; l[0] = n; r[n] = 0; r[0] = 1; l[n] = n - 1;
	ll mx = 0, sum = 0;
	for(int i = 1; i <= n; ++i)sum += a[i];
	for(int k = 1; k <= n / 2; ++k){
		while(q.size() && de[q.top().second])q.pop();
		if(q.size()){
			mx += q.top().first;
			int x = q.top().second;
			del(x);
			q.pop(); q.push(pli(val[x], x)); 
		}
		printf("%lld\n",sum - mx);
	}
	return 0;
}
posted @   Chen_jr  阅读(44)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示