发现已经错过最美的花期|

ricky_lin

园龄:3年8个月粉丝:11关注:2

【题解】CF1819 合集

CF1819A Constructive Problem

标签:思维题 C

你考虑这道题中判 No 显然有两种情况:

  • 如果说 mexn 的话,即我们的所有数都是必不可少不能更改的,那么就是 No
  • 如果说原序列中有 mex+1 那么我们就可以发现添加 mex 显然会有很大的问题,我们显然要将所有的 mex+1 的区间替换为 mex,并且保证其他的数的 mex 和原序列的 mex 相同。

code:

#include<bits/stdc++.h>
using namespace std;
const int NN = 2e5 + 8;
int t,n;
int a[NN];
int b[NN];
int sta[NN],top;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);top = 0;
for(int i = 1; i <= n; ++i) scanf("%d",&a[i]),b[i] = a[i];
sort(b+1,b+1+n);
int mex = 0;
for(int i = 1; i <= n; ++i)
if(b[i] == mex) ++mex;
if(mex == n){puts("No");continue;}
for(int i = 1; i <= n; ++i) if(a[i] == mex+1) sta[++top] = i;
if(top == 1 || top == 0){puts("Yes");continue;}
int cnt = 0;
for(int i = 1; i < sta[1]; ++i) b[++cnt] = a[i];
for(int i = sta[top] + 1; i <= n; ++i) b[++cnt] = a[i];
sort(b+1,b+1+cnt);
int mex2 = 0;
for(int i = 1; i <= cnt; ++i)
if(b[i] == mex2) ++mex2;
if(mex2 == mex) puts("Yes");
else puts("No");
}
return 0;
}

CF1819B The Butcher

标签:思维题 C+

我们可以清楚地发现,最后剩下的矩形有个性质:

  • 最后一定有一个切出来的子矩形包含原矩形的长/宽
  • 接着我们可以发现,最后切出来的所有子矩形的最长的长和宽才有可能是原矩形的长或宽
  • 由以上性质可以得到,我们可能的原矩形个数不超过 2

如何 check 一个矩形是否能被拼出来呢?

  • 我们显然就是找长或宽和现在矩形相同的,然后将现在的矩形减去这个子矩形。
  • 如果最后减不了/减多了就是不能拼凑出来的

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8;
int t;
int n;
bool vis[NN];
ll a[NN],b[NN];
map<int,vector<int> > MPa,MPb;
bool check(ll x,ll y){
MPa.clear();MPb.clear();
for(int i = 1; i <= n; ++i)
MPa[a[i]].push_back(i),MPb[b[i]].push_back(i),vis[i] = 0;
while(x != 0 && y != 0){
auto xx = MPa.find(x),yy = MPb.find(y);
if(xx != MPa.end()){
int get = 0;
for(int i : xx->second){
if(!vis[i]){
y -= b[i];
vis[i] = 1;
get = 1;
if(y < 0) return false;
}
}
if(get) continue;
}
if(yy != MPb.end()){
int get = 0;
for(int i : yy->second){
if(!vis[i]){
x -= a[i];
vis[i] = 1;
get = 1;
if(x < 0) return false;
}
}
if(get) continue;
}
return false;
}
return true;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
ll maxa = 0,maxb = 0,sum = 0;
for(int i = 1; i <= n; ++i){
scanf("%lld%lld",&a[i],&b[i]);
maxa = max(maxa,a[i]),maxb = max(maxb,b[i]);
sum += a[i] * b[i];
}
int visa = 0,visb = 0;
if(sum % maxa == 0) visa = check(maxa,sum/maxa);
if(maxa != sum/maxb && sum % maxb == 0) visb = check(sum/maxb,maxb);
printf("%d\n",visa + visb);
if(visa) printf("%lld %lld\n",maxa,sum/maxa);
if(visb) printf("%lld %lld\n",sum/maxb,maxb);
}
}

CF1819C The Fox and the Complete Tree Traversal

标签:思维题 B | 图论 C

你考虑我们手搓一堆样例可以十分困难地得到性质:

  • 如果树不是毛毛虫就会寄掉(反正我是画了一张草稿纸,提出又 ban 掉了无数条性质才找到的)

知道了这个性质之后,输出方案就很好输出了,每次跳两个,如果中间那个点有儿子,就先把中间点的儿子跳完了,再去那两格。

code:

#include<bits/stdc++.h>
using namespace std;
const int NN = 2e5 + 8;
struct Edge{
int to,next;
}edge[NN << 1];
int head[NN],cnt;
void init(){
memset(head,-1,sizeof(head));
cnt = 1;
}
void add_edge(int u,int v){
edge[++cnt] = {v,head[u]};
head[u] = cnt;
}
bool noo;
int sonc[NN],ssc[NN];
void dfs(int u,int fa){
sonc[u] = 0,ssc[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs(v,u);
++sonc[u];
if(ssc[u] != 0 && sonc[v] > 0) noo = 1;
ssc[u] = (sonc[v] > 0) ? v : ssc[u];
}
return;
}
void dfs2(int u,int fa,int now){
if(now) printf("%d ",u);
if(!now){
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(v == fa || v == ssc[u]) continue;
printf("%d ",v);
}
}
if(ssc[u]) dfs2(ssc[u],u,now^1);
if(now){
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(v == fa || v == ssc[u]) continue;
printf("%d ",v);
}
}
if(!now) printf("%d ",u);
}
int n;
int main(){
scanf("%d",&n);init();
for(int i = 1,u,v; i < n; ++i){
scanf("%d%d",&u,&v);
add_edge(u,v);add_edge(v,u);
}
dfs(1,1);
int rt = 1;
while(ssc[rt] != 0) rt = ssc[rt];
for(int i = head[rt]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(sonc[v] == 0) rt = v;
}
noo = 0;
dfs(rt,rt);
if(noo){puts("No");return 0;}
puts("Yes");
dfs2(rt,rt,1);
}

CF1819D Misha and Apples

标签:DP B | 思维题 B

显然地,我们的序列最后一次清空越早,我们的最后的答案更加优秀。

考虑求出来对每一个 i 求出 lim 表示我们能够将到 i 目前为止的最后一次清空最早在 lim 处。同时对于每个 i 求一个 cli 表示在 i 处清空是否可能

如果说当前的 ilimi 中的一个集合重复了且为 mx,为了不让 i 被清除,那么我们就要将 mx 清除掉。

即将 lim 变为 mx 及其后面的第一个能够被清除的位置。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int NN = 2e5 + 8;
int n,m,k;
int pre[NN],cl[NN],las[NN];
vector<int> a[NN];
void solve(){
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; ++i){
scanf("%d",&k);
a[i].resize(k);
for(int j = 0; j < k; ++j) scanf("%d",&a[i][j]),las[a[i][j]] = 0;
pre[i] = pre[i-1] + (k==0);
}
cl[0] = 1;
int lim = 0;
for(int i = 1; i <= n; ++i){
int mx = 0;
for(int j : a[i]) mx = max(mx,las[j]),las[j] = i;
if(lim < mx || pre[lim] < pre[i]) cl[i] = 1;
else cl[i] = 0;
while(lim < mx || !cl[lim]) ++lim;
}
if(pre[lim] < pre[n]) printf("%d\n",m);
else{
int sum = 0;
while(lim + 1 <= n) sum += a[++lim].size();
printf("%d\n",sum);
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
solve();
}
}

CF1819E Roads in E City

标签:思维题 A | 图论 C

我们可以先找到一个全是特殊边的最小生成树:

  • 我们对于每一条边都断一次,然后对该边的两个点都询问 20 次,可以证明,如果说该边是当前特殊边图中的桥,有 99.9999% 的几率会询问到 0 (即删边后,两个点不连通)
  • 如果不是特殊边上的桥/不是特殊边,那么回答一定全是 1,那么我们便删去这条边。可以知道,我们删去的这条边如果是特殊边,可能生成新特殊边图中的桥。

这样,我们就花费了 O(40m) 次询问,找到了一个特殊边生成树。

但是,这个时候,还有一些特殊边没有被找出来。

我们如何判断一个边是不是特殊边呢?

  • 我们对于一条非树边,删去树上非树边链接的两个点之间的一条边,建上非树边,然后再按上述方式询问两点是否联通,如果连通,该边就是特殊边,不连通即为普通边。

最后我们便用了 O(80m40n) 的代价找到了所有边的类型。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,NN = 2e3 + 8,MM = 2e3 + 8;
int T;
int n,m;
int type[NN],dep[NN],F[NN];
struct Edge{
int u,v;
}edge[MM];
vector<Edge> tr[NN];
bool check(int i){
int u = edge[i].u,v = edge[i].v;
bool flag = 0,ot;
for(int i = 1; i <= 20; ++i){
printf("? %d\n",u);fflush(stdout);
scanf("%d",&ot);flag |= !ot;
printf("? %d\n",v);fflush(stdout);
scanf("%d",&ot);flag |= !ot;
if(flag) return flag;
}
return flag;
}
void dfs(int u, int fa){
for(auto &e : tr[u]){
int v = e.v;
if(v == fa) continue;
F[v] = e.u;
dep[v] = dep[u] + 1;
dfs(v, u);
}
}
int main(){
scanf("%d",&T);
while(T--){
memset(type,0,sizeof(type));
memset(dep,0,sizeof(dep));
memset(F,0,sizeof(F));
for(int i = 1; i <= n; ++i) tr[i].clear();
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; ++i) scanf("%d%d",&edge[i].u,&edge[i].v);
for(int i = 1; i <= m; ++i){
int u = edge[i].u, v = edge[i].v;
printf("- %d\n",i);fflush(stdout);
if(check(i)){
tr[u].push_back({i,v});
tr[v].push_back({i,u});
printf("+ %d\n",i);fflush(stdout);
type[i] = true;
}
}
dfs(1, 0);
for(int i = 1; i <= m; ++i)
if(!type[i]){
int u = edge[i].u, v = edge[i].v;
if(dep[u] < dep[v]) swap(u, v);
printf("- %d\n",F[u]);fflush(stdout);
printf("+ %d\n",i);fflush(stdout);
if(!check(i)) type[i] = true;
printf("- %d\n",i);fflush(stdout);
printf("+ %d\n",F[u]);fflush(stdout);
}
printf("! ");
for(int i = 1; i <= m; ++i) printf("%d ",type[i]);
puts("");fflush(stdout);
int f; scanf("%d",&f); if(f == 0) return 0;
}
}
posted @   ricky_lin  阅读(36)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 有我 周深
有我 - 周深
00:00 / 00:00
An audio error has occurred.

作词 : 唐恬/闫光宇

作曲 : 钱雷

编曲 : 赵兆/付虹宇

制作人 : 赵兆

出品 : 共青团中央宣传部

版权 : 中国青少年新媒体协会

制作单位 : 能量悦动音乐

发行单位 : 银河方舟StarNation

出品人 : 郭峰

总监制 : 汤杰

总策划 : 钟亚楠

总统筹 : 金慧子

音乐监制 : 李天鹏/李三木

制作执行 : 张不贰/高聪怡

项目宣发 : 肖健/张国党/孙小千/戴胤/孙雯璟

音乐推广 : 代诗琪/杜思潮/马越/程铁峰/傅之豪

钢琴 : 赵兆

吉他 : 伍凌枫

贝斯 : 韩阳

鼓 : 武勇恒

合唱设计 : 赵兆

合唱 : 凡尔赛合唱团

人声录音 : 耿潇微

人声录音室 : 55TEC Studio Beijing

配唱 : 徐威@52Hz Studio (Shanghai)

混音 : 李游(小骷髅)@55TEC Studio Beijing

海报 : 格子

特别鸣谢 : 周深工作室

世界问 你是谁 来自哪 请回答

爱什么 梦什么 去何方 请回答

答案有 一百年的时光

我来自 硝烟中 课桌旁 的太阳

我来自 硝烟中 课桌旁 的太阳

他和她 宣的誓 迎的仗

来自那 燃烧的 和我一样 的年华

来自世间 一对平凡的夫妻 身旁

来自世间 一对平凡的夫妻 身旁

来自昨天 谁以青春赴万丈 理想

我是寸土 不让的 家乡啊

我是绝不 低头的 倔强啊

接过万千热血 的初衷

当有对答世界 的音量

要怎么形容明天 像我一样

要怎么形容明天 像我一样

承风骨亦有锋芒 有梦则刚

去何方 去最高 的想象

前往皓月星辰 初心不忘

那未来如何登场 有我担当

那未来如何登场 有我担当

定是你只能叫好 那种辉光

护身旁 战远方 有我啊

我的名字就是 站立的地方

Wu~

我的样子 就是 明天的模样

我是朝阳 落在乡间听书声 朗朗

我是朝阳 落在乡间听书声 朗朗

我是屏障 为谁挡一程厄运 的墙

我要一生 清澈地 爱着啊

我要长歌 领着风 踏着浪

朝着星辰大海 的方向

当有对答世界 的音量

要怎么形容明天 像我一样

要怎么形容明天 像我一样

承风骨亦有锋芒 有梦则刚

去远方 去最高 的想象

前往皓月星辰 初心不忘

那未来如何登场 有我担当

那未来如何登场 有我担当

定是你只能叫好 那种辉光

护身旁 战远方 有我啊

一生骄傲为我 站立的地方

Wu~

我的样子 就是 中国的模样

Wu~~~ Wu~~~

当炬火 去化作那道光

“谨以此歌献给一代代不负时代重托的中国青年”

“谨以此歌献给一代代不负时代重托的中国青年”