The 1st Universal Cup. Stage 12: Ōokayama

news/2024/9/19 3:46:01/文章来源:https://www.cnblogs.com/cjjsb/p/18416735

Preface

久违地训练,因为昨天 ICPC 网络赛打的太唐不得不上点强度了

回到这场本身,由于中途发现了两个题被搬到去年暑假前集训队内赛了,导致经典提前没事干

2h15min 过了六个题后(有两个是原)就开始对着 L,M 发呆,虽然最后 4h45min 的时候把 M 开出来了,但还是说明做难题的水平不够(评价是霓虹场是这样的,好多 Counting 没办法发力)

由于这场题很多因此就只写过了的题/计划补的题了


A. XOR Tree Path

签到,读完题就发现可以设状态 \(f_{x,0/1}\) 表示在点 \(x\) 的子树内,修改的叶子数量为偶数/奇数时最多有几个黑点,转移显然

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,a[N],x,y,f[N][2]; vector <int> v[N];
inline void DFS(CI now=1,CI fa=0)
{bool flag=1;for (auto to:v[now]) if (to!=fa){DFS(to,now);if (flag){for (RI i=0;i<2;++i) f[now][i]=f[to][i]; flag=0;} else{int g[2]={0,0};for (RI p=0;p<2;++p) for (RI q=0;q<2;++q)g[p^q]=max(g[p^q],f[now][p]+f[to][q]);for (RI i=0;i<2;++i) f[now][i]=g[i];}}++f[now][a[now]^1];
}
int main()
{scanf("%d",&n);for (RI i=1;i<=n;++i) scanf("%d",&a[i]);for (RI i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);DFS(),printf("%d",max(f[1][0],f[1][1]));//for (RI i=1;i<=n;++i) printf("f[%d][0] = %d; f[%d][1] = %d\n",i,f[i][0],i,f[i][1]);return 0;
}

B. Magical Wallet

祁神开场写的神秘模拟+ DP,我题目都没看

#include<bits/stdc++.h>
using namespace std;const int INF = 1e9+5;
const int N = 1e4+5;
int n, x, A[105];
int dp[105][N];void chmax(int &x, int a) {x = max(x, a);
}int strToInt(const string &str) {int sz = str.size();int res = 0, bas=1;for (int i=0; i<sz; ++i, bas*=10) {res += (str[i]-'0')*bas;}return res;
}string intToStr(int x) {string res;while (x>0) res += (char)('0'+x%10), x/=10;return res;
}signed main() {ios::sync_with_stdio(0); cin.tie(0);cin >> n >> x;for (int i=1; i<=n; ++i) cin >> A[i];auto makeSet = [&](int val) {vector<int> res;string X = intToStr(val);sort(X.begin(), X.end());do {res.push_back(strToInt(X));} while (next_permutation(X.begin(), X.end())); return res;};vector<int> vec = makeSet(x);// printf("vec:"); for (int u : vec) printf("%d ", u); puts("");for (int i=0; i<=n; ++i) for (int j=0; j<10000; ++j) dp[i][j] = -INF;for (int u : vec) dp[0][u]=0;for (int i=1; i<=n; ++i) {for (int j=0; j<10000; ++j) {chmax(dp[i][j], dp[i-1][j]); int val = j-A[i];if (val < 0) continue;vec = makeSet(val);// if (dp[i-1][j]>=0) {printf("val=%d vec:", val); for (int u : vec) printf("%d ", u); puts("");}for (int u : vec) chmax(dp[i][u], dp[i-1][j]+1);}}int ans = 0;for (int j=0; j<10000; ++j) chmax(ans, dp[n][j]);cout << ans << '\n';return 0;
}

E. Five Med Sum

就是 这个题,做法直接看当时写的吧

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,mod=998244353;
int n,a[5][N],id[5],ans;
inline void inc(int& x,CI y)
{if ((x+=y)>=mod) x-=mod;
}
signed main()
{//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);RI i,j,k,s; for (scanf("%lld",&n),i=0;i<5;++i)for (j=1;j<=n;++j) scanf("%lld",&a[i][j]),a[i][j]=5LL*a[i][j]+i;for (i=0;i<5;++i) sort(a[i]+1,a[i]+n+1);for (i=0;i<5;++i) for (s=0;s<(1<<4);++s){int cur=0; for (j=0;j<4;++j) if ((s>>j)&1) ++cur;if (cur!=2) continue; cur=0;for (j=0;j<5;++j) if (i!=j) id[j]=(s>>cur)&1,++cur;for (j=1;j<=n;++j){int ret=1; for (k=0;k<5;++k) if (i!=k){int coef=lower_bound(a[k]+1,a[k]+n+1,a[i][j])-a[k]-1;if (id[k]) coef=n-coef; ret=1LL*ret*coef%mod;}inc(ans,1LL*ret*((a[i][j]-i)/5LL)%mod);}}return printf("%lld",ans),0;
}

G. Range NEQ

虽然算是 Counting,但恰好是牢闪勉强会一点的简单容斥和简单多项式,推了会也就会了

有禁区的排列计数直接上棋盘多项式,不难发现就是在一个边长为 \(n\times m\) 的棋盘上放 \(n\times m\) 个棋子,其中禁区为按主对角线排布的 \(n\) 个单元,每个单元为 \(m\times m\) 的矩形

考虑容斥计数,枚举有 \(i\) 个棋子放在禁区中,同时令 \(f(i)\) 表示放 \(i\) 个棋子在禁区中的方案数,则答案为:

\[\sum_{i=0}^{n\times m} (-1)^i\times f(i)\times (n\times m-i)! \]

现在考虑计算 \(f(i)\),不难想到一个朴素的 DP,令 \(g_{i,j}\) 表示处理了前 \(i\) 个单元,此时一共放了 \(j\) 个棋子的方案数

考虑在一个单元里放 \(k\in[0,m]\) 个棋子的方案数为 \((C_m^k)^2\times k!\) ,以此为系数进行转移,即得到复杂度为 \(O(n^2\times m^2)\) 的 DP

但这样做显然太劣了,考虑生成函数,对于一个单元格的生成函数 \(G(x)=\sum_{k=0}^m (C_m^k)^2\times k!\times x^k\),不难发现 \(G^n(x)\) 就是我们想要的 \(f(i)\)

由于 \(G(x)\) 的次数为 \(n\times m\),因此可以大力转化为点值后快速幂后转回去,只用写 NTT 即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=1<<21,mod=998244353;
int n,m,f[N],fact[N],ifac[N];
inline void inc(int& x,CI y)
{if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{if ((x-=y)<0) x+=mod;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{fact[0]=1; for (RI i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;ifac[n]=quick_pow(fact[n]); for (RI i=n-1;i>=0;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{if (n<0||m<0||n<m) return 0;return 1LL*fact[n]*ifac[m]%mod*ifac[n-m]%mod;
}
namespace Poly
{int rev[N],lim,p;inline void init(CI n){for (lim=1,p=0;lim<=n;lim<<=1,++p);for (RI i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<p-1);}inline void NTT(int *f,CI opt){for (RI i=0;i<lim;++i) if (i<rev[i]) swap(f[i],f[rev[i]]);for (RI i=1;i<lim;i<<=1){int m=i<<1,D=quick_pow(3,opt==1?(mod-1)/m:mod-1-(mod-1)/m);for (RI j=0;j<lim;j+=m){int W=1; for (RI k=0;k<i;++k,W=1LL*W*D%mod){int x=f[j+k],y=1LL*f[i+j+k]*W%mod;f[j+k]=f[i+j+k]=x; inc(f[j+k],y); dec(f[i+j+k],y);}}}if (!~opt){int Inv=quick_pow(lim);for (RI i=0;i<lim;++i) f[i]=1LL*f[i]*Inv%mod;}}
}
int main()
{scanf("%d%d",&n,&m); init(n*m);for (RI i=0;i<=m;++i) f[i]=1LL*C(m,i)*C(m,i)%mod*fact[i]%mod;Poly::init(n*m); Poly::NTT(f,1);for (RI i=0;i<Poly::lim;++i) f[i]=quick_pow(f[i],n);Poly::NTT(f,-1); int ans=0;//for (RI i=0;i<=n*m;++i) printf("%d%c",f[i]," \n"[i==n*m]);for (RI i=0;i<=n*m;++i){int tmp=1LL*f[i]*fact[n*m-i]%mod;if (i&1) dec(ans,tmp); else inc(ans,tmp);}return printf("%d",ans),0;
}

J. Make Convex Sequence

直接把做法写在题目名里了

首先不难发现题目中给的限制等价于找到的所有点 \((i,A_i)\) 形成一个下凸壳

手玩发现我们对所有 \((i,R_i)\) 求下凸壳后,检验它是否和每一个线段有交即可,这样一定是最优的

#include<bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;const int N = 3e5+5;
int n, L[N], R[N];
int stk[N], tp=-1;
signed main() {ios::sync_with_stdio(0); cin.tie(0);cin >> n;for (int i=1; i<=n; ++i) cin >> L[i];for (int i=1; i<=n; ++i) cin >> R[i];auto check = [&](int p, int a, int b) {return (R[a]-R[p])*(b-p) < (R[b]-R[p])*(a-p);};auto check2 = [&](int p, int a, int b) {return (L[a]-R[p])*(b-p) < (R[b]-R[p])*(a-p);};for (int i=1; i<=n; ++i) {while (tp>0 && !check(stk[tp-1], stk[tp], i)) --tp;stk[++tp] = i;}bool ok=true;int cur=1;for (int i=1; i<=n; ++i) {while (cur<=tp && stk[cur]<i) ++cur;if (!check2(stk[cur-1], i, stk[cur])) {ok=false; break;}}cout << (ok ? "Yes\n" : "No\n");return 0;
}

L. Many Products

看过题人数是个应该要会的 Counting,等过两天有时间再补吧


M. Colorful Graph

只能说这题上来就发现是个经典的 DAG 最小可重复路径覆盖,然后偷懒了想去网上找标准的做法,结果发现会连出 \(O(n^2)\) 条边被卡空间

后面只能自己想结果发现是个很 trivial 的建图,首先还是把原 DAG 用拆分二分图的模型来建,具体地:

  • \(S\)\(i\) 连容量为 \(1\) 的边,且 \(n+i\)\(T\) 连容量为 \(1\) 的边;
  • 若原图中存在 \(x\to y\) 的边,则 \(x\)\(n+y\) 连容量为 \(\infty\) 的边;
  • \(n+i\)\(i\) 连容量为 \(\infty\) 的边;

这样建图后跑出的最大流上的边一定在原 DAG 的路径覆盖上,求方案数的话就沿着选中的边 DFS 一下,用并查集把同色的点合并一下即可

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=7005,INF=1e9;
int n,m,x,y,dfn[N],low[N],idx,stk[N],top,vis[N],bel[N],tot,fa[N],col[N]; vector <int> v[N];
inline void Tarjan(CI now)
{dfn[now]=low[now]=++idx; stk[++top]=now; vis[now]=1;for (auto to:v[now]) if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);else if (vis[to]) low[now]=min(low[now],dfn[to]);if (low[now]==dfn[now]){bel[now]=++tot; vis[now]=0;while (stk[top]!=now) bel[stk[top]]=tot,vis[stk[top--]]=0; --top;}
}
namespace Network_Flow
{const int NN=15005,MM=30005;struct edge{int to,nxt,v,tp;}e[MM<<1]; int cnt=1,head[NN],cur[NN],dep[NN],s,t;inline void addedge(CI x,CI y,CI z){//printf("%d -> %d  (%d)\n",x,y,z);e[++cnt]=(edge){y,head[x],z,z}; head[x]=cnt;e[++cnt]=(edge){x,head[y],0,-z}; head[y]=cnt;}#define to e[i].toinline bool BFS(void){memset(dep,0,(t+1)*sizeof(int));dep[s]=1; queue <int> q; q.push(s);while (!q.empty()){int now=q.front(); q.pop();for (RI i=head[now];i;i=e[i].nxt)if (e[i].v&&!dep[to]) dep[to]=dep[now]+1,q.push(to);}return dep[t];}inline int DFS(CI now,CI tar,int dis){if (now==tar) return dis; int ret=0;for (RI& i=cur[now];i&&dis;i=e[i].nxt)if (e[i].v&&dep[to]==dep[now]+1){int dist=DFS(to,tar,min(dis,e[i].v));if (!dist) dep[to]=INF;dis-=dist; ret+=dist; e[i].v-=dist; e[i^1].v+=dist;if (!dis) return ret;}if (!ret) dep[now]=INF; return ret;}inline bool travel(CI now,int& tar){//printf("%d\n",now);if (now>tot){for (RI i=head[now];i;i=e[i].nxt)if (to==t&&e[i].tp>0&&e[i].v!=e[i].tp){++e[i].v; tar=now; return 1;}}for (RI i=head[now];i;i=e[i].nxt){//printf("to = %d; v = %d; tp = %d\n",to,e[i].v,e[i].tp);if (e[i].tp>0&&e[i].v!=e[i].tp){++e[i].v;if (travel(to,tar)) return 1;}}return 0;}#undef toinline int Dinic(int ret=0){while (BFS()) memcpy(cur,head,(t+1)*sizeof(int)),ret+=DFS(s,t,INF); return ret;}
};
using namespace Network_Flow;
inline int getfa(CI x)
{return fa[x]!=x?fa[x]=getfa(fa[x]):x;
}
int main()
{scanf("%d%d",&n,&m);for (RI i=1;i<=m;++i) scanf("%d%d",&x,&y),v[x].push_back(y);for (RI i=1;i<=n;++i) if (!dfn[i]) Tarjan(i);for (RI x=1;x<=n;++x) for (auto y:v[x])if (bel[x]!=bel[y]) addedge(bel[x],tot+bel[y],INF);//for (RI i=1;i<=n;++i) printf("%d%c",bel[i]," \n"[i==n]);s=0; t=2*tot+1; for (RI i=1;i<=tot;++i)addedge(s,i,1),addedge(tot+i,t,1),addedge(tot+i,i,INF);for (RI i=1;i<=tot;++i) fa[i]=i;Dinic(); int num=0;for (RI i=head[s];i;i=e[i].nxt)if (e[i].tp>0&&e[i].v!=e[i].tp){int st=e[i].to,tar;++e[i].v; travel(st,tar);//printf("%d %d\n",st,tar);fa[getfa(st)]=getfa(tar-tot);}for (RI i=1;i<=tot;++i) if (getfa(i)==i) col[i]=++num;for (RI i=1;i<=n;++i) printf("%d ",col[getfa(bel[i])]);return 0;
}

N. XOR Reachable

就是 这个题,做法直接看当时写的吧


Postscript

犹记得去年这个时候一周 VP 四场还外加 CF/ATC 的补题,现在我一周啥也不干每天就是白兰

只能说该进入备战状态了,不出意外的话今年应该是个人算竞生涯的最后一舞了,希望能不留遗憾吧

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

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

相关文章

李尚杰的第一次作业

这次作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc这个作业的目标 熟悉博客的建立,向老师/助教介绍自己并阐述对课程的期待姓名-学号 李尚杰-2022329301146一、个人简介 (一)基本介绍我叫李尚杰,来自22自动化1班,浙江杭州人。我爱好摄影、旅游、看电影、健身…

数木莫系且的旭酱买水问题

dut开区用,在别的情况下该博客无效数木莫系且的旭酱买水问题 创中的招新又双叒叕开始了,“数木莫系且”要开始出招新题了,“数木莫系且”的36位老东西为了想招新题整天废寝忘食、绞尽脑汁、抓耳挠腮、呕心沥血,甚至连水都忘记喝了。“数木莫系且“的不时用日语小声发癫的旭…

字符编码发展史1 — ASCII和EASCII

1. 字符集与字符编码1.1. 字符集 1.2. 字符编码 1.3. 两者的关系2. 字符编码的发展历史2.1. 第一个阶段 ASCII编码2.1.1. ASCII 2.1.2. EASCII1. 字符集与字符编码 1.1. 字符集 字符集(Charcater Set或Charset): 是一个系统支持的所有抽象字符的集合,也就是一系列字符的集合…

[JVM]对象创建过程

Java 对象的创建过程 Java对象创建的过程主要分为五个步骤,下面我将详细介绍这五个步骤。 Step1:类加载检查 虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且会检查这个符号引用所指向的类是否已经完成加载、连接和初始化,…

教小模型进行推理

https://arxiv.org/abs/2212.08410 思维链提示在基础层面上是如此成功,以至于它产生了一些被称为 x 链现象的东西。谷歌研究院探索了如何使用 llm 为现有数据集生成 CoT 数据本体,然后如何在 CoT 上微调较小的语言模型。 介绍 众所周知,思维链提示提高了大型语言模型的推理能…

[WesternCTF2018]shrine

打开题目就得到了python代码 import flask import os #导包 app = flask.Flask(__name__) #创建一个flask实例, app.config[FLAG] = os.environ.pop(FLAG) #从操作系统的环境变量中读取名为FLAG的值,并将其存储在Flask的配置中,POP:读取后删除该环境变量@app.route(/) #定义…

MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法

原文:MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法 参考:Connection Java - MySQL : Public Key Retrieval is not allowed在使用 MySQL 8.0 时重启应用后提示com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Public Key Retrieva…

MobaXterm 密钥生成器

1、MobaXterm 密钥生成器,代码仓库地址: https://gitcode.com/gh_mirrors/mo/MobaXterm-keygen/blob/master/MobaXterm-Keygen.py 2、也可以用我打包好的exe程序,不用安装python环境: https://pan.baidu.com/s/1jo85pQc_kfWhcYmZcc49CQ 提取码:ws10 3、源码:#/usr/bin/e…

Linux引导启动程序(boot)

概述 本章主要描述boot/目录中的三个汇编代码文件,见列表6-1所示。正如在前一章中提到的,这三个文件虽然都是汇编程序,但却使用了两种语法格式。bootsect.s和setup.s是实模式下运行的16位代码程序,采用近似于Intel的汇编语言语法并且需要使用Intel 8086汇编编译器和连接器as86和…

9、const修饰指针

*代表指针,这样有助于记忆和区别这三种