最失败的一集。

C

开题顺序搞错,不小心先开了C,以为是A。还好C不难。

题意大概是在给定的数组最后添一个数(所有数两两不同),再自定义一个数 \(k\) ,数组中每个数可以加上若干个 \(k\) ,最后使得所有数字相等。要求加 \(k\) 的次数最少。

如果不加最后一个数,那么显然把所有的数加到与最大的那一个数相等最优,\(k\) 就是所有数与最大值的差的 \(\gcd\) 。

考虑加上最后一个数:

假设最后一个数不是最大值,那么只要让它与最大值的差值最小且这个差值是 \(k\) 的倍数。可以直接枚举 \(1\) 到 \(n\) 每个 \(k\) 的倍数是否出现过。最劣的情况差为 \(nk\) ,答案 \(+n\)。

假设最后一个数是最大值,那么其他每个数都要加一次 \(k\) ,答案 \(+n\) 这和以上那种情况中最劣的相同,可以不考虑。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5,MOD=998244353;
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
int n;cin>>n;
vector<int> A(n);
for(int i=0;i<n;i++) cin>>A[i];
sort(A.begin(),A.end());
if(n==1) cout<<1<<endl;
else
{
int g=A[1]-A[0],ans=0;
for(int i=2;i<n;i++)
g=gcd(g,A[i]-A[i-1]);
map<int,int> mp;
for(int i=0;i<n;i++) ans+=(A[n-1]-A[i])/g,mp[(A[n-1]-A[i])/g]++;
for(int i=1;i<=n;i++) if(!mp[i])
{
ans+=i;
break;
}
cout<<ans<<endl;
}
}
}

A

签到题,给一个01串,可以再01或10之间插入0,可以在00或11之间插入1,问最终能否使0的个数多于1。

只要不是全1就可以。

B

细节题。给定 \(n,P,l,t\) ,\(n\) 是总天数,\(P\) 是 \(n\) 天内要拿的分,\(l\) 是上一节课的分数,\(t\) 是做一次作业的分数。

一天做多做两次作业,上一节课。并且作业只会在第 \((1+7*k)\) 天布置一次,可以再布置之后的任意一天做。

问做多能休息几天,也就是最小化做作业和上课的天数。

一开始的想法是二分答案,但写完之后发现会爆 long long 。所以不行。

补:好像是可以二分的,是我自己范围取大了挂了

其实只要分类讨论,显然把所有作业放到最后几天完成最优(符合实际),并且做作业的几天去上课显然不亏。

于是判断最后几天做完作业并且在那几天去上课能否满足 \(P\) 分要求,满足则再看能否少上几天,不满足就用上课填余下的分数。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5,MOD=998244353;
int n,P,l,t,ans;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--)
{
cin>>n>>P>>l>>t;
int tasks=(n-1)/7+1;
if(tasks*t+(tasks+1)/2*l>=P)
{
cout<<n-(P+2*t+l-1)/(2*t+l)<<endl;
}
else
{
P-=tasks*t+(tasks+1)/2*l;
n-=(tasks+1)/2;
cout<<n-(P+l-1)/l<<endl;
}
}
}

好了,后面都是我没敲出来题了。但是思想不难,可做。

但为什么放三道数据结构?

D

题意:机器人按照给出的包含UDRL的字符串从 \((0,0)\) 开始行动,\(q\) 个询问包含 \(l,r,x,y\) ,问翻转行动序列的从 \(l\) 到 \(r\) 的子串,机器人是否经过点 \((x,y)\) 。

首先可以预处理整条路线,翻转一段行动序列就是把图形局部旋转 \(180°\) 。但路线旋转 \(180°\) 不好维护,于是想到可以旋转每个询问的点,这样就不用对序列进行操作。

于是可以维护每一个经过的点被机器人经过的所有时间,用这些时间与每个询问的 \(l,r\) 作比较,可以得到答案。

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=2e5+5,MOD=998244353;
template<class T>inline void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(!isdigit(ch)) f=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=f?-x:x;
}
template<class T>inline void write(T x)
{
if(x<0) return putchar('-'),write(-x);
if(x>9) write(x/10);
putchar('0'+x%10);
}
#define trans(x,y) ((x+n)*(2*n+1)+(y+n))
int p[N];
unordered_map<int,vector<int>> mp;
pair<int,int> poi[N];
pair<int,int> rotate(pair<int,int> A,pair<int,int> O)
{
return make_pair(O.first-A.first,O.second-A.second);
}
pair<int,int> operator + (const pair<int,int> x,const pair<int,int> y)
{
return make_pair(x.first+y.first,x.second+y.second);
}
signed main()
{
int n,q;
read(n),read(q);
poi[0]=make_pair(0,0);
p[0]=trans(0,0);
mp[p[0]].push_back(0);
for(int i=1,x=0,y=0;i<=n;i++)
{
char c=getchar();
while(c!='U'&&c!='D'&&c!='R'&&c!='L') c=getchar();
if(c=='U') y++;
if(c=='D') y--;
if(c=='R') x++;
if(c=='L') x--;
poi[i]=make_pair(x,y);
// cout<<poi[i+1].first<<','<<poi[i+1].second<<endl;
p[i]=trans(x,y);
mp[p[i]].push_back(i);
}
while(q--)
{
int x,y,l,r,fl=0,id,id_ro;
cin>>x>>y>>l>>r;
pair<int,int> now=make_pair(x,y);
pair<int,int> now_ro=rotate(now,poi[l-1]+poi[r]);
id=trans(now.first,now.second),id_ro=trans(now_ro.first,now_ro.second);
#define tmp mp[id]
#define tmp_ro mp[id_ro]
// vector<int> tmp=mp[trans(now.first,now.second)];
// vector<int> tmp_ro=mp[trans(now_ro.first,now_ro.second)]; //vector 赋值复杂度就萎了
if(!tmp.empty())
{
if(tmp[0]<l||tmp[tmp.size()-1]>=r) fl=1;
}
if(!tmp_ro.empty())
{
int pos=lower_bound(tmp_ro.begin(),tmp_ro.end(),l)-tmp_ro.begin();
if(pos<tmp_ro.size()&&tmp_ro[pos]<r) fl=1;
}
if(fl) puts("YES");
else puts("NO");
}
}

E

题意:若 \(A\)、\(B\) 是字符串,

\[C(A,B)=
\begin{cases}
C(A_{2,n},B_{1,n-1}),\,\,A_1=B_n\\
A+B,\,\,\text{otherwise}\\
\end{cases}
\]

给定 \(n\) 个字符串求:

\[\sum_{i=1}^{n}\sum_{j=1}^{n}C(s_i,s_j)
\]

trie树裸题,每次把一个串丢进trie中统计一次答案,再将串反向插入trie。

但必须反着再做一次,还要加上每个串自己与自己匹配的贡献。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5,MOD=998244353;
string S[N];
struct node{
int son[26];
ll num,cnt;
}trie[N];
int n,rt,tot;
ll ans;
string s;
void insert(int &id,int pos)
{
if(!id) id=++tot;
trie[id].cnt++;
trie[id].num+=s.size()-pos;
if(pos>=s.size()) return;
insert(trie[id].son[s[pos]-'a'],pos+1);
}
void query(int id,int pos)
{
if(!id) return;
int Son=trie[id].son[s[pos]-'a'];
if(pos==s.size()-1)
{
ans+=trie[id].num-(trie[Son].num+trie[Son].cnt)+(trie[id].cnt-trie[Son].cnt)+trie[Son].num;
// cout<<ans<<" : "<<trie[id].num<<" "<<(trie[Son].num+trie[Son].cnt)<<" " <<(trie[id].cnt-trie[Son].cnt)<<" "<<trie[Son].num-trie[Son].cnt<<endl;
return;
}
ans+=trie[id].num-(trie[Son].num+trie[Son].cnt)+(s.size()-pos)*(trie[id].cnt-trie[Son].cnt);
// cout<<Son<<" "<<trie[id].num<<" "<<(trie[Son].num+trie[Son].cnt)<<" " <<(s.size()-pos)*(trie[id].cnt-trie[Son].cnt)<<endl;
query(Son,pos+1);
}
void solve()
{
query(rt,0);
// cout<<s<<"?"<<ans<<endl;
reverse(s.begin(),s.end());
insert(rt,0);
}
void cul(string s)
{
for(int i=0;i<s.size();i++)
if(s[i]!=s[s.size()-i-1])
{
ans+=2*(s.size()-i);
break;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>S[i],cul(S[i]);
for(int i=1;i<=n;i++) s=S[i],solve();
memset(trie,0,sizeof(trie));
rt=tot=0;
for(int i=n;i;i--) s=S[i],solve();
cout<<ans<<endl;
}

F

题意:给定一棵带点权的树,\(q\) 次询问 \(x,y,k\) 问在 \(x\) 与 \(y\) 之间的路径上是否存在一些点异或和为 \(k\) 。

部分点权异或和为k,很容易联想到线性基,但是线性基很难支持区间询问,可以考虑用数据结构维护它。但是如果用倍增维护线性基的话复杂度可能达到三只log,不可行。

但是考虑到线性基实际上是至多 \(20\) 个线性方程,说明每一个线性基最多被插入 \(20\) 次。

因此可以考虑维护从每一个节点往上依次将点权插入线性基时,会对线性基产生改变的几个值。每个节点的线性基最多对应 \(20\) 个点。

但是直接暴力往上找的话复杂度会爆炸,于是可以考虑每个节点从父节点转移。

具体实现就是每个节点的线性基先插入自己的点权,再枚举父节点存储的若干个可以插入线性基的点,插入当前点的线性基。

显然,对每一次询问可以拆成两条从下往上的路径,直接暴力枚举 \(x,y\) 存储的若干个点,只要在到lca的路径上就插入针对当前询问新建的线性基。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,B=20,MOD=998244353;
struct L_base{
int bit[B+1];
void clear()
{
memset(bit,0,sizeof(bit));
}
int reduce(int x)
{
for(int i=B;i>=0;i--)
if(x&(1<<i)) x^=bit[i];
return x;
}
bool insert(int x)
{
x=reduce(x);
if(!x) return 0;
for(int i=B;i>=0;i--)
if(x&(1<<i))
{
bit[i]=x;
return 1;
}
}
bool check(int x)
{
return reduce(x)==0;
}
}base[N];
vector<int> to[N],con[N];
int fa[N][21],cnt,ord_in[N],ord_out[N],A[N],n;
void dfs(int x,int pre)
{
fa[x][0]=pre;
for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; base[x].insert(A[x]);
con[x].push_back(x);
for(int val:con[pre])
if(base[x].insert(A[val]))
con[x].push_back(val); ord_in[x]=++cnt;
for(auto y:to[x])
if(y!=pre) dfs(y,x);
ord_out[x]=++cnt;
}
bool is_ancester(int x,int y)
{
if(x==0) return 1;
return ord_in[x]<=ord_in[y]&&ord_out[x]>=ord_out[y];
}
int LCA(int x,int y)
{
if(is_ancester(y,x)) return y;
for(int i=20;i>=0;i--)
if(!is_ancester(fa[y][i],x))
y=fa[y][i];
return fa[y][0];
}
bool query(int x,int y,int k)
{
int lca=LCA(x,y);
L_base now;now.clear();
now.insert(A[lca]);
for(int val:con[x]) if(!is_ancester(val,lca)) now.insert(A[val]);
for(int val:con[y]) if(!is_ancester(val,lca)) now.insert(A[val]);
return now.check(k);
}
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];
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
to[u].push_back(v);
to[v].push_back(u);
}
dfs(1,0);
int q;cin>>q;
while(q--)
{
int x,y,val;cin>>x>>y>>val;
cout<<(query(x,y,val)?"Yes":"No")<<endl;
}
}

总结

这次比赛最失败的一点就是发现E是trie裸题之后急于求成没想清楚细节就开始狂敲一通,结果不仅调不出一点,而且把做D的时间的耗没了。总之就是对trie的结构不够熟悉,细节上把握不到位,代码能力不够。

Educational Codeforces Round 159 总结的更多相关文章

  1. [Educational Codeforces Round 16]E. Generate a String

    [Educational Codeforces Round 16]E. Generate a String 试题描述 zscoder wants to generate an input file f ...

  2. [Educational Codeforces Round 16]D. Two Arithmetic Progressions

    [Educational Codeforces Round 16]D. Two Arithmetic Progressions 试题描述 You are given two arithmetic pr ...

  3. [Educational Codeforces Round 16]C. Magic Odd Square

    [Educational Codeforces Round 16]C. Magic Odd Square 试题描述 Find an n × n matrix with different number ...

  4. [Educational Codeforces Round 16]B. Optimal Point on a Line

    [Educational Codeforces Round 16]B. Optimal Point on a Line 试题描述 You are given n points on a line wi ...

  5. [Educational Codeforces Round 16]A. King Moves

    [Educational Codeforces Round 16]A. King Moves 试题描述 The only king stands on the standard chess board ...

  6. Educational Codeforces Round 6 C. Pearls in a Row

    Educational Codeforces Round 6 C. Pearls in a Row 题意:一个3e5范围的序列:要你分成最多数量的子序列,其中子序列必须是只有两个数相同, 其余的数只能 ...

  7. Educational Codeforces Round 9

    Educational Codeforces Round 9 Longest Subsequence 题目描述:给出一个序列,从中抽出若干个数,使它们的公倍数小于等于\(m\),问最多能抽出多少个数, ...

  8. Educational Codeforces Round 37

    Educational Codeforces Round 37 这场有点炸,题目比较水,但只做了3题QAQ.还是实力不够啊! 写下题解算了--(写的比较粗糙,细节或者bug可以私聊2333) A. W ...

  9. Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship Time Limit: 2000 mSec P ...

  10. Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems(动态规划+矩阵快速幂)

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems Time Limit: 3000 mSec P ...

随机推荐

  1. Ds100p -「数据结构百题」21~30

    21.P4172 [WC2006]水管局长 SC 省 MY 市有着庞大的地下水管网络,嘟嘟是 MY 市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从 \(x ...

  2. Vue源码学习(八):生命周期调用

    好家伙,   Vue源码学习(七):合并生命周期(混入Vue.Mixin) 书接上回,在上一篇中,我们已经实现了合并生命周期 现在,我们要在我们的初始化过程中,注册生命周期 1.项目目录  红框为本篇 ...

  3. Docker V24 及 Docker Compose V2 的安装及使用

    前言 Docker 是一款流行的开源容器化平台,使用 Docker 可以有效地隔离应用程序和系统环境,使得应用程序在不同的环境中具有相同的行为 Docker Compose 是一个用于定义和管理多个 ...

  4. Chapter 6. Build Script Basics

    Chapter 6. Build Script Basics 6.1. Projects and tasks Everything in Gradle sits on top of two basic ...

  5. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-18-处理鼠标拖拽-上篇

    1.简介 本文主要介绍两个在测试过程中可能会用到的功能:在selenium中宏哥介绍了Actions类中的拖拽操作和Actions类中的划取字段操作.例如:需要在一堆log字符中随机划取一段文字,然后 ...

  6. [CISCN 2019华东南]Web11

    看到下面connection 里面的内容有一点像抓包出来的 就抓包试试 似乎感觉也没有什么用 看到这个东西,那么就想到改IP 添加X-Forwarded-For:127.0.0.1 发现这个IP随着我 ...

  7. 不写代码、构建一个开源的 ChatGPT,总共需要几步?|Hugging News #1020

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  8. 我与Vue.js 2.x 的七年之痒

    --过去日子的回顾(这是个副标题) --其实这是篇广告软文(这是个副副标题) 以下是一些牢骚和感悟,不感兴趣的可以滑倒最下面,嘻嘻. 每每回忆起从前,就感觉时间飞逝,真切的感受到了那种课本中描述的白驹 ...

  9. Acwing76场周赛

    题目链接 这次还是只做出来两道题,前两题都挺简单的,注意第二题需要开long long不开会wa,代码粘上来,以后可能会看吧 第一题 #include<iostream> #include ...

  10. 一个基于Vue模型的表单生成器

    哈喽,我是老鱼,一名致力于在技术道路上的终身学习者.实践者.分享者! Vuetify Form Base是一个基于模型的表单生成器,目的是提供一个工具,以便以较少的努力从任何模型数据生成可编辑的表单, ...