NOIP2024加赛6
一签三计数,罚坐了。
草莓
简单贪心,随便贪就过了。
点此查看代码
#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 LOCAL FILE *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 #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 LOCAL FILE *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; 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(); }
考虑正解,将
发现转移时有三种,
设
具体的,用
时间复杂度
点此查看代码
#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 LOCAL FILE *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(); }
博弈
假设最后留下的三个数分别为
分三种情况讨论。
-
三个值都相同,即
。那么先手直接输。 -
三个值都不相同,即
,此时先手必胜。证明:如果
,则先手可以直接操作 到 ,则先手必胜。考虑
和 ,发现这两种情况是等价的,此处只考虑 。将其移动,假设
移动后的点为 , 移动后的点为 ,由于 时无影响,不考虑,考虑 的。假如后手可以移动使得自己为处于必胜态,假设此时
的对应点为 , 的对应点为 ,那么先手就可以直接移动到 ,使得后手无法处于必胜态。QED.
-
三个值中只有两个相同,发现
和 等价,不妨设 。此时当且仅当 为2的偶数次幂时先手必胜。证明:先手必胜时当且仅当
,否则就会使得后者存在 的状态使得后手必胜。假设
表示 时先手是否必胜,有 。此时可以发现当且仅当 的最后一位 为偶数位时, 。
然后分别求
点此查看代码
#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 LOCAL FILE *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维护那
没写。
p
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18555575
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本