Educational Codeforces Round 159 总结
最失败的一集。
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\) 是字符串,
\begin{cases}
C(A_{2,n},B_{1,n-1}),\,\,A_1=B_n\\
A+B,\,\,\text{otherwise}\\
\end{cases}
\]
给定 \(n\) 个字符串求:
\]
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 总结的更多相关文章
- [Educational Codeforces Round 16]E. Generate a String
[Educational Codeforces Round 16]E. Generate a String 试题描述 zscoder wants to generate an input file f ...
- [Educational Codeforces Round 16]D. Two Arithmetic Progressions
[Educational Codeforces Round 16]D. Two Arithmetic Progressions 试题描述 You are given two arithmetic pr ...
- [Educational Codeforces Round 16]C. Magic Odd Square
[Educational Codeforces Round 16]C. Magic Odd Square 试题描述 Find an n × n matrix with different number ...
- [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 ...
- [Educational Codeforces Round 16]A. King Moves
[Educational Codeforces Round 16]A. King Moves 试题描述 The only king stands on the standard chess board ...
- Educational Codeforces Round 6 C. Pearls in a Row
Educational Codeforces Round 6 C. Pearls in a Row 题意:一个3e5范围的序列:要你分成最多数量的子序列,其中子序列必须是只有两个数相同, 其余的数只能 ...
- Educational Codeforces Round 9
Educational Codeforces Round 9 Longest Subsequence 题目描述:给出一个序列,从中抽出若干个数,使它们的公倍数小于等于\(m\),问最多能抽出多少个数, ...
- Educational Codeforces Round 37
Educational Codeforces Round 37 这场有点炸,题目比较水,但只做了3题QAQ.还是实力不够啊! 写下题解算了--(写的比较粗糙,细节或者bug可以私聊2333) A. W ...
- 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 ...
- 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 ...
随机推荐
- Ds100p -「数据结构百题」21~30
21.P4172 [WC2006]水管局长 SC 省 MY 市有着庞大的地下水管网络,嘟嘟是 MY 市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从 \(x ...
- Vue源码学习(八):生命周期调用
好家伙, Vue源码学习(七):合并生命周期(混入Vue.Mixin) 书接上回,在上一篇中,我们已经实现了合并生命周期 现在,我们要在我们的初始化过程中,注册生命周期 1.项目目录 红框为本篇 ...
- Docker V24 及 Docker Compose V2 的安装及使用
前言 Docker 是一款流行的开源容器化平台,使用 Docker 可以有效地隔离应用程序和系统环境,使得应用程序在不同的环境中具有相同的行为 Docker Compose 是一个用于定义和管理多个 ...
- Chapter 6. Build Script Basics
Chapter 6. Build Script Basics 6.1. Projects and tasks Everything in Gradle sits on top of two basic ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-18-处理鼠标拖拽-上篇
1.简介 本文主要介绍两个在测试过程中可能会用到的功能:在selenium中宏哥介绍了Actions类中的拖拽操作和Actions类中的划取字段操作.例如:需要在一堆log字符中随机划取一段文字,然后 ...
- [CISCN 2019华东南]Web11
看到下面connection 里面的内容有一点像抓包出来的 就抓包试试 似乎感觉也没有什么用 看到这个东西,那么就想到改IP 添加X-Forwarded-For:127.0.0.1 发现这个IP随着我 ...
- 不写代码、构建一个开源的 ChatGPT,总共需要几步?|Hugging News #1020
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...
- 我与Vue.js 2.x 的七年之痒
--过去日子的回顾(这是个副标题) --其实这是篇广告软文(这是个副副标题) 以下是一些牢骚和感悟,不感兴趣的可以滑倒最下面,嘻嘻. 每每回忆起从前,就感觉时间飞逝,真切的感受到了那种课本中描述的白驹 ...
- Acwing76场周赛
题目链接 这次还是只做出来两道题,前两题都挺简单的,注意第二题需要开long long不开会wa,代码粘上来,以后可能会看吧 第一题 #include<iostream> #include ...
- 一个基于Vue模型的表单生成器
哈喽,我是老鱼,一名致力于在技术道路上的终身学习者.实践者.分享者! Vuetify Form Base是一个基于模型的表单生成器,目的是提供一个工具,以便以较少的努力从任何模型数据生成可编辑的表单, ...