Educational Codeforces Round 138
这把是真的丢了大脸。
$\color{Green}{★}\ \ $ 表示赛时做出。
$\color{Yellow}{★}\ \ $ 表示赛后已补。
$\color{Red}{★}\ \ $ 表示 \(\mathcal{To\ be\ solved}\)。
A
\(\color{Green}{★}\ \ \mathcal{*Difficulty: ?}\)
Description
\(n \times n\) 的棋盘,有 \(m\) 原本不会互相攻击的车,询问是否能移动一辆车且依然不会互相攻击。
Solution
显然,只要 \(m \ne n\),就必然有解。
code
void work(){
int n,m;cin>>n>>m;
cout<<((n^m)?"YES\n":"NO\n");
}
B
$\color{Green}{★}\ $ \(\ \mathcal{*Difficulty: ?}\)
Description
\(n\) 个怪物,血量等于数组 \(a\),被打死时给相邻怪物回 \(b_i\) 的血,求最少要打的血量。
Solution
显然,只要无限壁咚边缘的怪,并把 \(b\) 中的最大值留到最后,就能使 \(b\) 数组造成的贡献最小。
最终答案为:\(\sum_{i=1}^n a_i+b_i - \max{b_i} (1 \le i \le n)\)
code
void work(){
int n;cin>>n;vi a(n),b(n);
L(i,0,n-1) cin>>a[i];L(i,0,n-1) cin>>b[i];
int ans=0;L(i,0,n-1) ans+=a[i]+b[i];
ans-=*max_element(all(b));cout<<ans<<'\n';
}
C
$\color{Yellow}{★}\ $ \(\ \mathcal{*Difficulty: ?}\)
Description
对给定数组进行 \(k\) 轮的游戏,在第 \(i\) 轮时,A 取走一个小于等于 \(k-i+1\) 的数字,B 对一个数加上 \(k-i+1\),问 \(k\) 的最大值。
Solution
首先,不难看出,在第 \(i\) 轮,无论 \(B\) 对什么数进行加,都能使被加的数在后面的轮次无法被删除。
所以对于 \(B\),最佳决策就是从小开始操作数,对于 \(A\),自然就是从大数开始删,每次选最大的满足条件的数删去即可。
因为 \(n \le 100\),所以完全可以模拟整个过程,时间复杂度 \(O(n^3)\)。
当然,因为满足单调性,所以可以二分答案,时间复杂度 \(O(n^2 \log_2n)\)。
code
bool sol(int k){
b.resize(n);
L(i,0,n-1) b[i]=a[i];
L(i,1,k){
int g=-1;R(j,n-1,0)
if(b[j]<=k-i+1&&(b[j]!=-1)){
g=b[j];b[j]=-1;break;
}
if(g==-1) return 0;
for(int &i:b) if(~i){i=-1;break;}
}return 1;
}void work(){
cin>>n;a.resize(n);
for(int &i:a) cin>>i;
sort(all(a));
L(i,0,n)
if(sol(i)) s=i;
else break;
cout<<s<<'\n';
}
D
$\color{Yellow}{★}\ $ \(\ \mathcal{*Difficulty: ?}\)
Description
对于数组 \(a\) 中所有元素,如果满足 \(\gcd(a_i,i)=1\),就可以删除 \(a_i\),然后更新后面元素的下标。
给定数组大小 \(n\) 和数大小范围 \(m\),求问数组大小在 \([1,n]\) 范围内,所有元素在 \([1,m]\) 范围内,能用不止一种方式删光整个数组的数组数量。
Solution
首先,无论数组如何,都能够无限删除第一个元素。
如果这是唯一的删除方法,那么其元素 \(a_i\) 必须满足:\(\gcd(a_i,j) \ (2\le j \le i)\),因为在下标改变的过程中,会从 \(i\) 逐步移动到 \(1\),一直不能删就只能一直互质。
所以,能够满足只有单一删除方式的数组中元素 \(i\) 的取值种类有
\[\left\lfloor \dfrac{m}{\prod_{j=2}^i j \cdot \text{isPrime}_j}\right\rfloor \]之后就是统计答案,每次加上全排列数,然后减去每个位置的满足单一删除的数值之积。
如果用了快速幂之类的算法统计答案,时间复杂度就是 \(O(n \log_2 n)\)。
如果预处理出幂表,就能做到 \(O(n)\) 的时间复杂度。
下面给出的是 \(O(n)\) 做法,仅展示核心代码。
code
signed main(){
FST;cin>>n>>m;prime_(n);
a.resize(n+1);a[0]=1;
L(i,1,n) a[i]=a[i-1]*m;
L(i,1,n){
if(isp[i]) g*=i;lst*=m/g;
ans+=a[i]-lst;
}cout<<ans;
}//用了封装的 modint
E
$\color{Yellow}{★}\ $ \(\ \mathcal{*Difficulty: ?}\)
Description
在 \(n \times m\) 的网格图中,加入一些障碍且所有障碍两两不相邻(四联通),原本已有一些障碍,求问是否能构造出一种障碍方案,使得不存在从第一行到最后一行的路径。
Solution
我的思路有点偏向于网络流。
”不存在路径“的要求就像网络流中的最小割,用障碍将图拦腰截断就行。
考虑建图,先标记所有原本已有的障碍的四联通,因为这些点是不能放障碍的。
然后对所有未被标记的点进行连边,因为障碍不能相邻,所以每个点对周围的四个角连边,边权由目标点是否原本有障碍决定。
然后像网络流那样引入一个源点和汇点。
源点向第一列的未标记点连边,最后一列的未标记点向汇点连边。
之后就可以跑 01BFS
或者 Dijskra
,如果汇点的距离不为无穷大说明有解。
至于输出方案,就要记录路径,并将路径上的点记录并输出即可。
时间复杂度:\(O(n m \log_2 n m)\)
code
#include <bits/stdc++.h>
using namespace std;
#define F(i) (i).first
#define S(i) (i).second
#define si(i) ((int)i.size())
#define pb push_back
#define vi vector<int>
#define pi pair<int,int>
#define id(x,y) (x*m+y)
#define all(x) (x).begin(),(x).end()
#define me(t,x) memset(t,x,sizeof(t))
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define R(i,j,k) for(int (i)=(j);i>=(k);(i)--)
#define FST ios::sync_with_stdio(0);cin.tie(0);
const int N=5e5+100,INF=1e9;
int n,m,st,ed,pre[N],dis[N];
bool vis[N];vector<bool>b[N];vector<pi>g[N];
vector<pi>d={{-1,0},{1,0},{0,-1},{0,1}};
vector<pi>k={{-1,-1},{1,1},{1,-1},{-1,1}};
void work(){
cin>>n>>m;
st=n*m;ed=n*m+1;
vector<string>s(n);
L(i,0,n) b[i].resize(m+1);
L(i,0,n) fill(all(b[i]),0);
L(i,0,ed) g[i].clear();
for(auto &i:s) cin>>i;
L(i,0,n-1) L(j,0,m-1)
if(s[i][j]=='#')
for(pi x:d){
int p=i+F(x),q=j+S(x);
if(p<0||q<0||p>=n||q>=m) continue;
b[p][q]=1;
}
L(i,0,n-1) L(j,0,m-1) if(!b[i][j])
for(pi x:k){
int p=i+F(x),q=j+S(x);
if(p<0||q<0||p>=n||q>=m||b[p][q]) continue;
g[id(i,j)].pb({id(p,q),s[p][q]=='.'});
}
L(i,0,n-1) if(!b[i][0]) g[st].pb({id(i,0),s[i][0]=='.'});
L(i,0,n-1) if(!b[i][m-1]) g[id(i,m-1)].pb({ed,0});
fill(dis,dis+n*m+5,INF);
fill(vis,vis+n*m+5,0);
fill(pre,pre+n*m+5,0);
deque<int>q;
q.push_back(st),dis[st]=0;
while(!q.empty()){
int u=q.front();q.pop_front();
if(vis[u]) continue;vis[u]=1;
for(pi x:g[u]){
if(dis[F(x)]<=dis[u]+S(x)) continue;
dis[F(x)]=dis[u]+S(x);pre[F(x)]=u;
if(!S(x)) q.push_front(F(x));
else q.push_back(F(x));
}
}if(dis[ed]==INF) return cout<<"NO\n",void();
cout<<"YES\n";
for(int i=ed;i^st;i=pre[i])
if(i<n*m) s[i/m][i%m]='#';
for(auto i:s) cout<<i<<'\n';
}signed main(){
FST;int t;cin>>t;
L(i,1,t) work();
}
F
$\color{Yellow}{★}\ $ \(\ \mathcal{*Difficulty: ?}\)
Description
给定一棵有 \(n\) 个节点的树,每个点有点权,初始全为 \(0\),进行 \(m\) 次操作,操作分两种:
-
输出给定节点 \(v\) 的权值。
-
给定节点 \(u,v\),权值 \(k\),距离 \(d\),对所有距离 \(u,v\) 之间的简单路径小于等于 \(d\) 的点的权值加上 \(k\)
Solution
暂时咕着。
code
#include <bits/stdc++.h>
using namespace std;
#define lb(x) (x&-x)
#define pb push_back
#define vi vector<int>
#define pi pair<int,int>
#define L(i,j,k) for(int (i)=(j);i<=(k);(i)++)
#define FST ios::sync_with_stdio(0);cin.tie(0);
const int N=2e5+100;
int n,m,tot,u,v,x,r;vi g[N];
int id[N],f[N],h[N],d[N],si[N],t[N],a[N],b[N];
struct BIT{
int c[N];void add(int x,int k){for(;x<=n;x+=lb(x)) c[x]+=k;}
int ask(int x){int s=0;for(;x;x-=lb(x)) s+=c[x];return s;}
}T[21];
void dfs1(int u,int fa){
f[u]=fa;si[u]=1;d[u]=d[fa]+1;
for(int v:g[u]) if(v^fa){
dfs1(v,u);si[u]+=si[v];
if(si[h[u]]<si[v]) h[u]=v;
}
}void dfs2(int u,int tp){
t[u]=tp;id[u]=++tot;
if(!h[u]) return ;dfs2(h[u],tp);
for(int v:g[u]) if(v^f[u]&&v^h[u]) dfs2(v,v);
}int lca(int x,int y){
while(t[x]^t[y])
if(d[t[x]]<d[t[y]]) y=f[t[y]];
else x=f[t[x]];return d[x]<d[y]?x:y;
}void change(int u,int v,int k,int x){
while(t[u]^t[v]){
if(d[t[u]]<d[t[v]]) swap(u,v);T[x].add(id[t[u]],k);
T[x].add(id[u]+1,-k);u=f[t[u]];
}if(d[u]>d[v]) swap(u,v);
T[x].add(id[u],k);T[x].add(id[v]+1,-k);
}int main(){
FST;cin>>n;L(i,1,n-1)
cin>>u>>v,g[u].pb(v),g[v].pb(u);
L(i,n+1,n+19) g[i].pb(i+1),g[i+1].pb(i);
g[n+1].pb(1);g[1].pb(n+1);n+=20;
dfs1(n,n);dfs2(n,n);cin>>m;
L(i,1,m){
int o,u,v,k,x;cin>>o;
if(o==1){
cin>>x;int g=0;L(j,0,20)
g+=T[j].ask(id[x]),x=f[x];
cout<<g<<'\n';
}else{
cin>>u>>v>>k>>x;change(u,v,k,x);
if(!x) continue;u=lca(u,v);
change(u,u,-k,x);int g=0;
L(j,0,x){
L(p,0,x-j) change(u,u,k,p);
if(g&&(j^x)) L(p,0,x-j-1)
change(g,g,-k,p);
g=u;u=f[u];
}
}
}
}
最近一直在下分,希望中国场能上回来点吧。
标签:Educational,int,cin,Codeforces,pb,color,138,id,define From: https://www.cnblogs.com/AIskeleton/p/16815050.html