VP比赛补题报告之“Codeforces Round 766 (Div. 2)”
比赛链接
VP成绩
比赛经过
赛后补题+分析
A. Not Shading
简要/形式化题意
一个
1.对于所有
2.对于所有
问:至少几次操作后使得对于给定的
题解
(以下为严格证明,考场上手捏小数据更快)
情况
情况
情况
时间复杂度:
AC code
#include<bits/stdc++.h>
using namespace std;
const int N=60;
int T,n,m,r,c,cnt;
char ch[N][N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--) {
cin>>n>>m>>r>>c;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) cin>>ch[i][j];
if(ch[r][c]=='B') {
cout<<0<<endl;
continue;
}
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) cnt+=(ch[i][j]=='B');
if(!cnt) {
cout<<-1<<endl;
continue;
}
cnt=0;
for(int i=1;i<=n;i++) cnt+=(ch[i][c]=='B');
for(int j=1;j<=m;j++) cnt+=(ch[r][j]=='B');
if(!cnt) {
cout<<2<<endl;
continue;
}
cout<<1<<endl;
}
return 0;
}
B. Not Sitting
简要/形式化题意
在
第一轮:甲在矩阵中选取
第二轮:乙在矩阵中选取
第三轮:甲在矩阵中选取
甲以
求对于所有整数
题解
最后一轮的决策显然比较好讨论,因为第二轮已经确定。那么对于第三轮,为使
由特殊到一般,考虑
当
以此类推,记矩阵
AC code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int T,n,m;
int cnt;
priority_queue<int>q;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--) {
cin>>n>>m;
cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
int num=0;
num=max(num,i+j-2);
num=max(num,i-1+m-j);
num=max(num,n-i+j-1);
num=max(num,n-i+m-j);
q.push(-num);
}
while(!q.empty()) {
cout<<-q.top()<<" ";
q.pop();
}
cout<<endl;
}
return 0;
}
C. Not Assigning
简要/形式化题意
给定一个无边权无根树,请为每条边赋边权,使得所有边数不大于
题解
对于所有边数为
对于所有边数为
对于一个度数为
那么一个简单的构造方案是从度数为
AC code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int T,n,u,v,ans[N];
int deg[N],flag[N];
map<pair<int,int>,int>Map;
vector<int>G[N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--) {
memset(deg,0,sizeof(deg));
memset(flag,0,sizeof(flag));
cin>>n;
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<n;i++) {
cin>>u>>v;
if(u>v) swap(u,v);
Map[make_pair(u,v)]=i;
G[u].push_back(v);
G[v].push_back(u);
deg[u]++;
deg[v]++;
}
bool f=false;
for(int i=1;i<=n;i++)
if(deg[i]>=3) {
cout<<-1<<endl;
f=true;
break;
}
if(f) continue;
int st;
for(int i=1;i<=n;i++)
if(deg[i]==1) {
st=i;
break;
}
int cnt=0,pre;
while(cnt<=n-1) {
cnt++;
pre=st;
flag[pre]=1;
for(int i=0;i<G[pre].size();i++) {
int now=G[pre][i];
if(flag[now]) continue;
st=now;
}
if(cnt&1) ans[Map[make_pair(min(st,pre),max(st,pre))]]=2;
else ans[Map[make_pair(min(st,pre),max(st,pre))]]=3;
}
for(int i=1;i<n;i++) cout<<ans[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++)
for(int j=0;j<G[i].size();j++)
Map[make_pair(min(i,G[i][j]),max(i,G[i][j]))]=0;
}
return 0;
}
D. Not Adding
简要/形式化题意
给定长度为
题解
题意很迷人,稍加转化可知,原问题是在问
首先,可以形成
那么瓶颈就在于如何高效的筛出原始
AC code
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,a[N],b[N],ans;
int gcd(int a,int b) {
return b?gcd(b,a%b):a;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
b[a[i]]=1;
}
for(int i=1;i<N;i++) {
int cnt=0,ex;
if(b[i]) continue;
for(int j=2;i*j<N;j++)
if(b[i*j]) {
cnt++;
if(cnt==1) ex=i*j;
else ex=gcd(ex,i*j);
}
if(ex==i) ans++;
}
cout<<ans;
return 0;
}
E. Not Escaping
简要/形式化题意
给定一个
题解
显然可以看出是一道二维线性
对于同行的,把绝对值拆掉:当
优化:对于决策点
得出:
考虑跨行的情况,对于有序五元组
那么这样做的时间复杂度
当然,状态的设计要改一改,记
AC code
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;
const int N=1e5+10;
int t,n,m,k,a,b,c,d,h,x[N];
vector<pair<int,int> >E1[N];
pair<int,int>F[3*N];
int dp[3*N];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--) {
int cnt=0;
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>x[i];
for(int i=1;i<=n;i++) E1[i].clear();
E1[1].push_back(make_pair(1,++cnt));
for(int i=1;i<=k;i++) {
cin>>a>>b>>c>>d>>h;
E1[a].push_back(make_pair(b,++cnt));
F[cnt]=make_pair(cnt+1,h);
E1[c].push_back(make_pair(d,++cnt));
}
E1[n].push_back(make_pair(m,++cnt));
for(int i=1;i<=cnt;i++) dp[i]=1e18;
dp[1]=0;
for(int i=1;i<=n;i++) {
sort(E1[i].begin(),E1[i].end());
int len=E1[i].size();
for(int j=1;j<len;j++)
dp[E1[i][j].se]=min(dp[E1[i][j].se],dp[E1[i][j-1].se]+x[i]*(E1[i][j].fi-E1[i][j-1].fi));
for(int j=len-2;j>=0;j--)
dp[E1[i][j].se]=min(dp[E1[i][j].se],dp[E1[i][j+1].se]+x[i]*(E1[i][j+1].fi-E1[i][j].fi));
for(int j=0;j<len;j++)
if(dp[E1[i][j].se]!=1e18&&F[E1[i][j].se].fi)
dp[F[E1[i][j].se].fi]=min(dp[F[E1[i][j].se].fi],dp[E1[i][j].se]-F[E1[i][j].se].se);
}
if(dp[cnt]<1e18) cout<<dp[cnt]<<endl;
else cout<<"NO ESCAPE"<<endl;
}
return 0;
}
F. Not Splitting
简要/形式化题意
给定一个
题解
看似无从下手,但可以发现如果从整个格子最中间的格点(注意,是格点),向相对的两边引两条关于该格点中心对称的两条线,就能将网格分成两个全等的部分。当然这个方法是充分且必要的,感性理解一下,本人不咋会证明这个抽象的东西。
总而言之,对与
回到原问题,最少需要拿走几张骨牌,本质上就是在问,最少会穿过几张骨牌。从图的角度看待,
至此,原问题被转化为,求一条经过中心格点且贯穿网格图(即
为了方便实现,
AC code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=510;
const int M=1e6+10;
int t,k,n,r1,c1,r2,c2;
int vis[M],d[M];
map<pair<int,int>,int>Map;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--) {
priority_queue<pair<int,int> >q;
cin>>n>>k;
for(int i=1;i<=(k+1)*(k+1);i++) d[i]=1e18;
for(int i=1;i<=(k+1)*(k+1);i++) vis[i]=0;
Map.clear();
for(int i=1;i<=n;i++) {
cin>>r1>>c1>>r2>>c2;
if(r1>r2) swap(r1,r2);
if(c1>c2) swap(c1,c2);
if(r1==r2) {
Map[make_pair((r1-1)*(k+1)+c2,r1*(k+1)+c2)]++;
Map[make_pair(r1*(k+1)+c2,(r1-1)*(k+1)+c2)]++;
}
if(c1==c2) {
Map[make_pair(r1*(k+1)+c1,r1*(k+1)+c1+1)]++;
Map[make_pair(r1*(k+1)+c1+1,r1*(k+1)+c1)]++;
}
}
d[k*k/2+k+1]=0;
q.push(make_pair(0,k*k/2+k+1));
while(!q.empty()) {
int x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=1;
vis[k*k+2*k+2-x]=1;
if(x<=k+1||x>k*(k+1)||x%(k+1)==1||x%(k+1)==0) {
cout<<n-d[x]<<endl;
break;
}
int y,z;
y=x-1,z=Map[make_pair(x,y)]+Map[make_pair(k*k+2*k+2-x,k*k+2*k+2-y)];
if(d[y]>d[x]+z) {
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
y=x+1,z=Map[make_pair(x,y)]+Map[make_pair(k*k+2*k+2-x,k*k+2*k+2-y)];
if(d[y]>d[x]+z) {
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
y=x+k+1,z=Map[make_pair(x,y)]+Map[make_pair(k*k+2*k+2-x,k*k+2*k+2-y)];
if(d[y]>d[x]+z) {
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
y=x-k-1,z=Map[make_pair(x,y)]+Map[make_pair(k*k+2*k+2-x,k*k+2*k+2-y)];
if(d[y]>d[x]+z) {
d[y]=d[x]+z;
q.push(make_pair(-d[y],y));
}
}
}
return 0;
}
考后反思
首先后两题没有充足的时间思考,毕竟只留了
补题的时候发现,这场比赛有很多是结论题,比如
总而言之就是:优化瓶颈和数据范围选算法;手造大小数据找规律猜结论。
结尾
考的还行~。
本文作者:2021hych
本文链接:https://www.cnblogs.com/2021hych/p/17512674.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步