NOIP2024加赛6

news/2024/12/28 14:13:07/文章来源:https://www.cnblogs.com/hzoi-Cu/p/18555575

一签三计数,罚坐了。

草莓

简单贪心,随便贪就过了。

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALFILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else// FILE *InFile = stdin,*OutFile = stdout;FILE *InFile = freopen("guiltiness.in","r",stdin),*OutFile = freopen("guiltiness.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 2e5 + 10;
int n,m,a[N],b[N];
inline void solve(){cin>>n>>m;rep(i,1,n-1,1) cin>>a[i];rep(i,1,m-1,1) cin>>b[i];sort(a+1,a+n,greater<int>());sort(b+1,b+m,greater<int>());ll ans = 0;int na = 1,nb = 1,ta = 0,tb = 0;while(na < n && nb < m){if(a[na] >= b[nb]) ans += 1ll*(tb+1)*a[na],na++,ta++;else ans += 1ll*(ta+1)*b[nb],nb++,tb++;}while(na < n) ans += 1ll*(tb+1)*a[na],na++,ta++;while(nb < m) ans += 1ll*(ta+1)*b[nb],nb++,tb++;cout<<ans;
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);solve();
}

三色

弱化版:[ARC074E] RGB Sequence

先考虑\(O(n^3)\)怎么做。

\(f_{i,j,k}\)表示上一个与\(a_{i}\)颜色不同的位置为\(j\),上一个与\(a_i,a_j\)颜色都不同的位置为\(k\)时的方案数。

发现一定有 \(i>j>k\)(当\(i=1\)时除外,此时\(j=k=0\)),且 \(f_{1,0,0}=3\)

考虑如何从 \(i\) 转移到 \(i+1\)

  1. \(a_{i+1}=a_{i}\),那么\(f_{i+1,j,k}+=f_{i,j,k}\)
  2. \(a_{i+1}=a_{j}\),那么\(f_{i+1,i,k}+=f_{i,j,k}\)
  3. \(a_{i+1}=a_{k}\),那么\(f_{i+1,i,j}+=f_{i,j,k}\)

考虑如何剔除不合法状态,其实就是将不合法的状态置为 \(0\),将一个形如 \((l,r,x)\) 的限制挂在 \(r\) 上,对\(x\)进行分讨。

  1. \(x=1\),那么\(j<l\)
  2. \(x=2\),那么\(k<l,j\le l\)
  3. \(x=3\),那么\(l\le k<j\)

保留这些合法状态,其他的置为 \(0\) 即可。

点此查看代码
//[ARC074E] RGB Sequence
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALFILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#elseFILE *InFile = stdin,*OutFile = stdout;// FILE *InFile = freopen("color.in","r",stdin),*OutFile = freopen("color.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 5e2 + 10,M = 1e6 + 10,mod = 1e9 + 7;
struct limit{int l,x;};
vector<limit> lim[N];
int n,m,f[N][N][N];
inline void solve(){cin>>n>>m;rep(i,1,n,1) vector<limit> ().swap(lim[i]);rep(i,1,m,1){int l,r,x;cin>>l>>r>>x;lim[r].push_back({l,x});}rep(i,0,n,1) rep(j,0,n,1) rep(k,0,n,1) f[i][j][k] = 0;f[1][0][0] = 3;rep(i,1,n,1){for(auto [l,x]:lim[i]) rep(j,0,i-1,1){int lmt = j-(!!j);rep(k,0,lmt,1){if(x == 1 && l <= j) f[i][j][k] = 0;if(x == 2 && (l <= k || j < l)) f[i][j][k] = 0;if(x == 3 && k < l) f[i][j][k] = 0;}}if(i == n) break;rep(j,0,i-1,1){int lmt = j - (!!j);rep(k,0,lmt,1){if(!f[i][j][k]) continue;f[i+1][j][k] = (f[i+1][j][k] + f[i][j][k])%mod;f[i+1][i][k] = (f[i+1][i][k] + f[i][j][k])%mod;f[i+1][i][j] = (f[i+1][i][j] + f[i][j][k])%mod;}}}int ans = 0;rep(j,0,n-1,1){int lmt = j - (!!j);rep(k,0,lmt,1) ans = (ans + f[n][j][k])%mod;}cout<<ans<<'\n';
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);int T = 1;while(T--) solve();
}

考虑正解,将\(j,k\)看做横纵两维,那么转移时要做的操作就是保留一个矩阵,然后将其他位置置为\(0\)

发现转移时有三种,\((j,k),(i,k),(i,j)\),第一种不用管,滚动数组自动继承,后两种发现都是\(i\),就相当于加入一行。

\(s_{i}=\sum\limits_{j=1}^nf_{now,i,j}+f_{now,j,i}\),因为矩阵是对称的,这样可以做到\(O(n)\)加入一行。

具体的,用\(a_i\)记录\(f_{now,i}\)这一行中没有删去的,用\(b_i\)记录\(f_{now,,j}\)这一列没有删去的位置,然后用\(p,q\)再分别映射回原位置即可。

时间复杂度\(O(T(n^2+m))\)

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALFILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else// FILE *InFile = stdin,*OutFile = stdout;FILE *InFile = freopen("color.in","r",stdin),*OutFile = freopen("color.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
#define eb emplace_back
#define int long long
const int N = 5e3 + 10,M = 1e6 + 10,mod = 1e9 + 7;
struct limit{int l,x;};
vector<limit> lim[N];
int n,m,s[N],t[N];
vector<int> f,p,q,a[N],b[N];
inline void insert(int x,int y,int val){if(!val) return;int sz = f.size();f.eb(val),p.eb(x),q.eb(y);a[x].eb(sz);b[y].eb(sz);s[x] = (s[x] + val + mod)%mod,s[y] = (s[y] + val + mod) % mod;
}
inline void solve(){cin>>n>>m;rep(i,1,m,1){int l,r,x;cin>>l>>r>>x;lim[r].push_back({l,x});}insert(0,0,1);rep(i,0,n,1){int pl = 0,pr = 1e9,ql = 0,qr = 1e9;for(auto [j,x]:lim[i]){if(x == 1) pr = min(pr,j-1);if(x == 2) pl = max(pl,j),qr = min(qr,j-1);if(x == 3) ql = max(ql,j);}rep(j,0,i,1){if(j >= pl && j <= pr) continue;for(int x:a[j]) s[p[x]] = ((s[p[x]] - f[x])%mod + mod)%mod,s[q[x]] = ((s[q[x]] - f[x])%mod + mod)%mod,f[x] = 0;vector<int> ().swap(a[j]);}rep(j,0,i,1){if(j >= ql && j <= qr) continue;for(int x:b[j]) s[p[x]] = ((s[p[x]] - f[x])%mod + mod)%mod,s[q[x]] = ((s[q[x]] - f[x])%mod + mod)%mod,f[x] = 0;vector<int> ().swap(b[j]);}if(i < n){rep(j,0,i,1) t[j] = s[j];rep(j,0,i,1) insert(i,j,t[j]);}}int ans = 0;rep(i,0,n,1){ans = (ans + s[i] + mod)%mod,s[i] = 0;vector<int> ().swap(a[i]);vector<int> ().swap(b[i]);vector<limit> ().swap(lim[i]);}vector<int> ().swap(f);vector<int> ().swap(p);vector<int> ().swap(q);cout<<ans*500000004ll%mod<<'\n';
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);int T;cin>>T;while(T--) solve();
}

博弈

假设最后留下的三个数分别为\(a,b,c\),容易发现三个数的真实值并无影响,不妨设\(a\le b\le c\)

分三种情况讨论。

  1. 三个值都相同,即\(a=b=c\)。那么先手直接输。

  2. 三个值都不相同,即\(a<b<c\),此时先手必胜。

    证明:如果\(b=\frac{a+c}{2}\),则先手可以直接操作\(a,c\)\(b\),则先手必胜。

    考虑\(b<\frac{a+c}{2}\)\(b>\frac{a+c}{2}\),发现这两种情况是等价的,此处只考虑\(b<\frac{a+c}{2}\)

    将其移动,假设\(a\)移动后的点为\(a^\prime\)\(c\)移动后的点为\(c^\prime\),由于\(a^\prime \le b\)时无影响,不考虑,考虑\(a^\prime = b\)的。

    假如后手可以移动使得自己为处于必胜态,假设此时\(a^\prime\)的对应点为\(a^{\prime\prime}\)\(c^\prime\)的对应点为\(c^{\prime\prime}\),那么先手就可以直接移动到\(a^{\prime\prime},c^{\prime\prime}\),使得后手无法处于必胜态。

    QED.

  3. 三个值中只有两个相同,发现\(a=b<c\)\(a<b=c\)等价,不妨设\(a=b<c\)。此时当且仅当\(lowbit(c-a)\)为2的偶数次幂时先手必胜。

    证明:先手必胜时当且仅当\((c-a)\bmod 2=0\),否则就会使得后者存在\(a<b<c\)的状态使得后手必胜。

    假设\(f_{n}\)表示\(c-a=n\)时先手是否必胜,有\(f_{n}=!f_{\frac{n}{2}}\)。此时可以发现当且仅当\(n\)的最后一位\(1\)为偶数位时,\(f_{n}=true\)

然后分别求\(a<b<c\)时的值和\(a=b<c\)时的答案即可。求\(a<b<c\)时直接容斥即可,求\(a=b<c\)的有两种做法,\(\log^2n\)\(map\)做法:直接对于每一位开map;\(\log n\)的trie树上dp做法,具体的,考虑将偶数位的加上,奇数位的减去即可。

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALFILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else// FILE *InFile = stdin,*OutFile = stdout;FILE *InFile = freopen("game.in","r",stdin),*OutFile = freopen("game.out","w",stdout);
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
const int N = 5e5 + 10;
struct Trie{int tree[N*60][2],tot,siz[N*60];inline void insert(ll x){siz[0]++;int p = 0;rep(i,0,63,1){int k = (x>>i)&1ll;if(!tree[p][k]) tree[p][k] = ++tot,siz[tot] = 0;p = tree[p][k];siz[p]++;}}inline ll solve(ll x){ll res = 0;int p = 0,dep = 0;rep(i,0,63,1){int k = (x>>i)&1ll;if(!tree[p][k]) break;p = tree[p][k];dep++;res += ((dep&1)?1:-1)*siz[p];}return res;}inline void clear(){rep(i,0,tot,1) tree[i][0] = tree[i][1] = 0;tot = 0;siz[0] = 0;}
}T;
int n,ct[N],tot;ll a[N],w[N];
inline ll C(int x){return x<2?0ll:1ll*x*(x-1)/2;}
inline void solve(){cin>>n;rep(i,1,n,1) cin>>a[i];sort(a+1,a+1+n);tot = 0;rep(i,1,n,1){int ed = i;while(ed < n && a[ed + 1] == a[ed]) ed++;ct[++tot] = ed-i+1,w[tot] = a[i];i = ed;}ll sum1 = 0,sum2 = 0,ans = 0;rep(i,1,tot,1){ll c = C(sum2) - sum1;ans += c*ct[i];sum2 += ct[i];sum1 += C(ct[i]);}T.clear();rep(i,1,n,1) T.insert(a[i]);rep(i,1,tot,1){if(ct[i] < 2) continue;ll c = C(ct[i]);ans += c*T.solve(w[i]);}cout<<ans<<'\n';
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);int T;cin>>T;while(T--) solve();
}

后缀数组

60pts:

用FHQ维护那\(m\)个修改操作,时间复杂度 \(m\log n\)。实现是参考文艺平衡树。然后统计所有 \(rk[a[i]+1]<rk[a[i+1]+1]\)的数量,答案是\(2^k\)

没写。

p

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/836997.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法

java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法@目录一、记录文件相关操作方法二、代码1.读取路径返回List<File>2.读取路径返回List<String>3.删除文件夹4.删除文件 一、记录文件相关操作方法 二、代…

一些再也不敢了的行为

前言:考完 CSP-S 2024 才总结出来的各种离谱错误。本文不讨论类似于在有环图上跑拓扑排序这种错误,直接说会见祖宗的行为。进入考场前检查好准考证和身份证等必要物品,笔者因为这个原因 \(2024\) 年联合省选被困在了门外。由于不是正式选手,最终被放了进去。如果当前电脑运…

什么是水鱼?三分钟教会你

"水鱼"是广西人最喜欢玩的酒桌游戏,它属于扑克牌的一种玩法,经过不断改良升级而来。如果你在广西不会水鱼,那喝酒就没有了灵魂。虽然广西名族很多,水鱼玩法不一样,但是同一个框架,内容不同而已。比如有些地方黑桃花色最大,有些地方红桃花色最大,这种一般玩2,…

Oracle Linux 9.5 正式版发布 - Oracle 提供支持 RHEL 兼容发行版

Oracle Linux 9.5 正式版发布 - Oracle 提供支持 RHEL 兼容发行版Oracle Linux 9.5 正式版发布 - Oracle 提供支持 RHEL 兼容发行版 Oracle Linux with Unbreakable Enterprise Kernel (UEK) & Red Hat compatible kernel (RHCK) 请访问原文链接:https://sysin.org/blog/o…

List集合按照由小到大排序或者由大到小排序

@目录背景原代码由小到大排序由大到小排序 背景原List<User>里面是无序的,比如从redis查找等情况,查出来的是无序的,现在想按照由小到大排序或者由大到小排序。原代码 List<User> list = new ArrayList<>(); list.add(new User(3, "c", new Dat…

pta两次大作业

PTA 两次大作业总结:详细分析与实践经验 前言 回顾这次的家具强电电路模拟程序大作业,它无疑是一次极具挑战的编程与设计经历。从最初简单的电路组件模拟,到后期复杂的多设备连接和精准的控制反馈,这个过程不仅让我掌握了许多技术技能,还在思维方式、问题解决能力以及系统…

mac安装maven3.8.8

问题描述 down了一个新应用, maven依赖总是加载不到, 本地仓库也能找到, 项目启动报错 org.apache.skywalking:apm-toolkit-trace:pom:5.0.0-RC-SNAPSHOT failed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repositor…

mac 安装maven

问题描述 down了一个新应用, maven依赖总是加载不到, 本地仓库也能找到, 项目启动报错 org.apache.skywalking:apm-toolkit-trace:pom:5.0.0-RC-SNAPSHOT failed to transfer from http://0.0.0.0/ during a previous attempt. This failure was cached in the local repositor…

一个基于 .NET 8.0 构建的简单、跨平台、模块化商城系统

前言 今天给大家分享一个基于 .NET 8.0 构建的开源免费(MIT License)、简单、跨平台、模块化的商城系统:Module Shop。 主要功能销售:订单、物流。 内容:首页配置、评论、回复。 配置:国家、用户、仓库、运费、高级设置。 商品:分类、品牌、单位、选项(销售属性)、属性…

IDEA如何新增一个模块和删除一个模块

前言 大家好,我是小徐啊。今天小徐要给大家介绍下IDEA里面如何新增和删除模块。在开发过程中,我有时候会遇到多模块的项目,有时候自己也要增加相应的模块,用不同的模块去开发不同的功能。那么该如何操作呢? 如何新增模块 首先,在IDEA中,将鼠标放在项目的根目录上,然后右…

从汇编看函数调用传参过程

1 示例代码 #include <stdio.h>int func(int param1 ,int param2,int param3) {int var1 = param1;int var2 = param2;int var3 = param3;printf("var1=%d,var2=%d,var3=%d",var1,var2,var3);return var1; }int main(int argc, char* argv[]) {int result = fu…

IDEA如何导入外部依赖的jar包

前言 大家好,我是小徐啊。今天小徐要给大家介绍下,在使用IDEA开发java应用时,如何导入第三方的jar包,注意不是通过maven的方式导入。这种情况就是这个jar包比较特殊,可能并不存在于仓库中,需要手动引入。 如何导入jar包 首先,我们需要在资源目录下新建一个文件夹,我一般…