2022NOIP A层联测13
A. QAQ
注意到状态数最多也就 于是用 直接爆力转移即可
题解说状态数为 级别,不会证
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. 游戏
交互题只是为了方便写 ?
用到哥德巴赫猜想
于是当 为偶数时, 如果 是质数,那么 个因子
否则他一定能够写成两个质数 的形式,于是有 个因子
如果 为奇数,那么当 为质数时,有 个因子
否则他可以写成 , 有 个因子
上面的情况说明了答案的上界,取最小的答案还要与他本身因子个数取
注意到 比较小时候需要一些特判,于是我干脆留下了考场暴力,免去讨论
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. 修仙
套路题,跟种树一毛一样,因为之前某天拉着 打过一天可反悔贪心,今天捡了个板子题
令 , 那么问题转化为选取 个不相邻的 使得他们的权值和最大,于是就完全是种树了
如果你想看看自己对可反悔贪心的理解程度,可以看看这个题单
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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!