D - Operator Precedence
求一个长度为 \(2n\) 的序列 \(a_{2n}\) 满足条件 \((a_1 × a_2)+(a_3 × a_4)+\ldots+(a_{2n-1} × a_{2n})=a_1×(a_2+a_3)×\ldots×(a_{2n-2}+a_{2n-1})×a_{2n}\)
solution
构造题显然找特殊规律。
考虑到乘法构造难度大于加法,可以从乘法开始考虑。
注意到不要求 \({a_i}\) 各不相等且 \(a_1×1×1×\ldots ×1×a_{2n}==a_1×a_{2n}\) ,考虑能不能令 \(a_{2n-2}+a_{2n-1}\) 都为 1。
显然任意钦定 \(a_{2n-2}+a_{2n-1}\) 的值之后,只剩未知数 \(a_1\) 和 \(a_{2n}\)。
再钦定其一解另一即可。
同理 \(a_1×0×0×\ldots ×0×a_{2n}==0\) ,考虑能不能令 \(a_{2n-2}+a_{2n-1}\) 都为 0。
解法同上。
G - Snake Move
给定 \(n × m\) 地图上的一条长度为 \(k\) 的贪吃蛇。每次操作可以控制贪吃蛇移动一步或者缩短一格蛇身。
对于每个位置,求从初始状态出发最少需要多少次操作使得蛇头到达该处。
Solution
甩个题解吧
每个操作都可以等价看作初始蛇身必然缩短 \(1\),并且同时控制蛇头移动一步或者不移动,因此蛇头到达每个位置的时间越早越好。
最短路建图,相邻格子连代价 \(1\) 的边。
如果一个位置在初始状态下不被蛇身占据,考虑按 Dijkstra 最短路算法第一次访问该点的时刻,蛇头一定不会与蛇身相交。
否则,对于初始状态下第 \(i (2 ≤ i ≤ k)\) 节蛇身所处的位置,显然必须操作 \(k − i\) 次后才能访问该点。因此松弛该点时,需要将最短路长度与
\(k − i\) 取 max。(这一部分没想到)
注:对于取 max 操作的 \(k\) 个点,使用另一个队列升序记录每个状态。那么 Dijkstra 算法的瓶颈——找距离最小的点可以通过比较两个队列的队首
\(\text{O}(1)\) 得到。
void Dij(){
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
q.push(make_pair(0,rt));Dis[rt]=0;memset(Dis,0x3f,sizeof Dis);
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u]) continue;vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(dis[to]){
if(Dis[to]>Dis[u]+k-dis[to]+1)
Dis[to]=Dis[u]+k-dis[to]+1,
q.push(make_pair(Dis[to],to));
}
else{
if(Dis[to]>Dis[u]+1)
Dis[to]=Dis[u]+1,
q.push(make_pair(Dis[to],to));
}
}
}
}
int main(){
n=read();m=read();k=read();
for(int i=1,x,y,tmp;i<=k;i++){
x=read();y=read();
tmp=(x-1)*m+y;dis[tmp]=i;
if(i==1) rt=tmp;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char s;cin>>s;
if(s=='.'){
for(int t=0;t<4;t++){
int tx=i+dx[t],ty=j+dy[t];
if(tx<0||tx>=n||ty<0||ty>=m||s=='#') continue;
add((i-1)*m+j,(tx-1)*m+ty);
}
}
}
}
Dij();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(Dis[(i-1)*m+j]!=0x3f) ans=(ans+qu(Dis[(i-1)*m+j],2))%Mod;
}
}
return 0;
}
H - Sugar Sweet II
给出 \(n\) 个按随机顺序发生的事件,每个事件可以描述为:若 \(a_i<a_{b_i}\),则 \(a_i\) 增加 \(w_i\)。
求每个数的期望。
Solution
先看官方题解:
要求的就是每个事件发生的概率。事件的依赖关系构成一棵基环树。
如果 \(a_i < a_{b_i}\),则事件 \(i\) 必然发生。
若 \(a_i ≥ a_{b_i} + w_{b_i}\),则事件 \(i\) 必然不发生。
否则,事件 \(i\) 发生当且仅当事件 \(b_i\) 在事件 \(i\) 之前发生。
则对这样子的事件而言,其发生的概率为 \(\frac{1}{L_i !}\),其中 \(L_i\) 为基环树上 \(i\) 到最近的,必定发生的祖先事件的概率。
如果离 \(i\) 最近的是一个必定不发生的事件,则事件 \(i\) 发生的概率为 \(0\)。
使用任何 \(\text{O}(n)\) 或者 \(\text{O}(n \text{log} n)\) 的算法处理出 \(L_i\) 即可。
为什么这么算呢,\(L_i!\) 其实就是 \(A_{L_i}^{L_i}\)。
即假如 C 必定发生,且 B 依赖 C ,A 依赖 B。如果 A 发生,那么在最终发生的时间排列中一定存在形如 C…B…A 的子序列,所以在算概率时要除以 3 的全排列。
void init(){
fact[0]=infact[0]=1;
for (int i=1; i<=500000; i++ ){
fact[i]=fact[i-1]*i%mod;
infact[i]=infact[i-1]*qmi(i,mod-2) % mod;
}
}
void solve() {
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i],b[i]--;
for(int i=0;i<n;i++) cin>>w[i];
for (int i=0;i<n;i++){
if (a[i]<a[b[i]]) ans[i]=a[i]+w[i],f[i]=1;
else if (a[i]>=a[b[i]]+w[b[i]]) ans[i]=a[i];
else {g[i]=b[i];rd[b[i]]++;}
}
for (int i=0;i<n;i++) {if(!rd[i]) tp.pb(i);}
for (int i=0; i<tp.size(); i++) {
int u=tp[i];cir[u]=0;int v=g[u];
if (v==-1) continue;rd[v]--;
if (!rd[v]) tp.pb(v);
}
for (int i=0;i<n;i++)
if (cir[i]) ans[i]=a[i];
for (int i=tp.size()-1;i>=0;i--) {
int u=tp[i];int v=g[u];
if (v==-1) dep[u] = 1;
else if (cir[v]) {
cir[u]=1;
ans[u]=a[u];
}
else if (f[v]){
dep[u]=dep[v] + 1;
ans[u]=a[u]+w[u]*c(n,dep[u])%mod*fact[n-dep[u]]%mod*infact[n]%mod;
f[u]=1;
}
else ans[u]=a[u];
}
for(int i=0;i<ans.size();i++) cout<<x%mod<<" \n";
}
int main() {
cin>>t;init();
while(t--){
cin>>n;
solve();
}
return 0;
}
J - Mysterious Tree
一棵树,可能是链或者菊花,每次询问一条边存在性,确定是链还是菊花。
一共有 \(\lceil{\frac{n}{2}}\rceil +3\) 次询问机会。
Solution
显然对于一条边 \((x,y)\),如果两端点的度数全为 \(1\) 则为链,否则为菊花图。
因此我们只需要找出一个存在的边并询问即可。
再考虑询问策略。
如果我们找到了一条存在的边 \((x,y)\),因为无法统计每个点的度数,因此只能再分别找出与 \(x,y\) 相连的点。
我们随机找一个点 \(p\),若图为菊花图则 \((p,x),(p,y)\) 必定有一个存在,反之可能不存在。若不存在则直接判断。
若存在(我们假设 \((p,x)\) 存在),则可以再随机找一个点 \(q\),若 \((q,x)\) 也存在则必定为菊花图,反之为链图。
因此我们通过 \((x,y)\) 来判断只需不超过 \(3\) 次提问。
那显然剩下的 \(\lceil{\frac{n}{2}}\rceil\) 次提问是为了找出 \((x,y)\)。
我们发现,若图为菊花图,那么形如 \((i,i+1)\) 的边必然存在,反之可能不存在。而进行全部询问次数正好与剩余次数相等。
因此不断询问,若存在则按上述步骤解,否则直接判断为链图即可。
M - V-Diagram
给一个 V 图,求一个连续子序列平均值最大的 V 图。
V 图指先严格单调减再严格单调增的序列。
Solution
我们考虑从完整序列的左右分别删除元素。
考虑左侧,若 \(a_1\) 删除后更优,因为 \(a_1>a_2\) 则 \(a_2\) 删除也会更优,因此左侧应删除到 \(a_{i-1}\)
右侧同理。
因此答案为 \([1,i-1],[i+1,n]\) 或者 \([1,n]\)。
标签:ICPC2023,Training,Ag,int,else,dep,事件,2n,Dis From: https://www.cnblogs.com/KnightL/p/18089265