AtCoder Grand Contest 011题解
\(A\)
直接按时间排序之后贪心就可以了
const int N=1e5+5;
int a[N],q[N],c,k,h,t,n,res;
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
scanf("%d%d%d",&n,&c,&k);
fp(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n);
h=1,t=0;
fp(i,1,n){
while(h<=t&&a[q[h]]<a[i]-k)++res,h=min(t+1,h+c);
q[++t]=i;
}
while(h<=t)++res,h=min(t+1,h+c);
printf("%d\n",res);
return 0;
}
\(B\)
发现吃的时候从小到大吃肯定是最优的,那么从小到大排个序,找到右边开始的第一个\(sum_{i-1}\times 2<a_i\)的位置即可
typedef long long ll;
const int N=1e5+5;
ll sum[N];int a[N],n;
int main(){
scanf("%d",&n);
fp(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n);
fp(i,1,n)sum[i]=sum[i-1]+a[i];
fd(i,n,1)if(a[i]>(sum[i-1]<<1))return printf("%d\n",n-i+1),0;
return 233;
}
\(C\)
把\(O(n)\)的图和\(O(n^2)\)的图分别记为\(S\)和\(T\)
首先把\(S\)中只有一个点的连通块特判掉,因为只要\(u\)这个联通块中只有一个点,那么\(T\)中任何一个包含\(u\)的点绝对不会和别的任何点相连
现在假设每一个连通块中有至少两个点,那么\(T\)中的一个点\((u,v)\)(\(u,v\)是否在同一连通块中都可以),绝对和所有形如\((u,w)\)的点在同一连通块中,其中\(v,w\)之间存在一条路径使其距离为偶数。这个很显然,因为只要\(v\)在走这条路径的过程中,\(u\)只要和一个与它相邻的点反复横跳就可以了。更进一步我们发现当\(v\)所在的连通块中存在奇环时\(w\)可以为整个连通块,否则只能为其中一部分点
那么对于\(S\)中每一个连通块,我们\(dfs\)一遍判断是否有奇环,那么对于两个不同的连通块,贡献分别为奇奇和奇偶\(1\),偶偶\(2\)(可以画个图自己理解一下),连通块相同类似讨论就行了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=5e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dis[N],deg[N],cnt[3],n,m,flag;ll res;
void dfs(int u,int d){
dis[u]=d;
go(u)if(dis[v]==-1)dfs(v,d^1);
else if(dis[v]!=dis[u]^1)flag=1;
}
int main(){
scanf("%d%d",&n,&m);
for(R int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v);
add(u,v),add(v,u),++deg[u],++deg[v];
}
memset(dis,-1,sizeof(dis));
fp(i,1,n)if(!deg[i])++cnt[2],++res;
else if(dis[i]==-1)flag=0,dfs(i,0),++cnt[flag],res+=2-flag;
res+=1ll*cnt[2]*(n-cnt[2])<<1;
res+=1ll*cnt[2]*(cnt[2]-1);
res+=1ll*cnt[0]*(cnt[0]-1)*2+1ll*cnt[0]*cnt[1]*2+1ll*cnt[1]*(cnt[1]-1);
printf("%lld\n",res);
return 0;
}
\(D\)
方便起见把\(A\)定义为\(1\),\(B\)定义为\(0\)
首先自己画个图手玩一下,发现一次操作之后,如果\(a_1=1\),那么变成\(a_1=0\),否则导致\(a_i=a_{i+1}^1\),且\(a_n=1\)
那么我们可以有一个\(O(k)\)的做法,每一次判断开头元素,如果是\(1\)直接改为\(0\),否则就把数列整体左移一位并区间取反以及在后面加数,区间取反记个标记就可以了,用一个队列去模拟就行
然后这样显然是不行的,所以如果这个队列的开头元素的位置大于\(n\)了我们就退出
手玩一下之后发现,如果\(n\)是偶数,那么整个序列必定形如\(01010101....0101\),且进行任何多次操作之后仍然长这样
再手玩一下之后发现,如果\(n\)是奇数,那么整个序列必定形如\(1010101010...101\),第一个位置根据操作次数的奇偶而定,而且操作两次之后会变回原样
那么讨论一下就可以了
//quming
#include<bits/stdc++.h>
#define R register
#define pb push_back
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e6+5;
char s[N];int n,k;
inline void print(R char *s){s[n]='\0',printf("%s\n",s);}
void solve(R int k){
R int i=1;
while(i<=n&&k--){
R int op=(i<=n?((i-1)&1):((n-1)&1));
if((s[i]=='A')^op){s[i]=(s[i]=='A'?'B':'A');continue;}
s[i+n]='A',++i;
}
if(i<=n){
R int op=(i-1)&1;
fp(k,i,i+n-2){
if(op)s[k]=(s[k]=='A'?'B':'A');
if(k+1>n)op^=1;
}
s[i+n-1]='A';
return print(s+i);
}
if(n&1^1){
fp(i,1,n)s[i]=((i&1)?'B':'A');
print(s+1);
return;
}
R int op=(n-1)&1;
if(op)--k;
s[n]=(k&1?'B':'A');
fp(i,1,n-1)s[i]=((i&1)?'A':'B');
reverse(s+1,s+1+n);
print(s+1);
}
int main(){
scanf("%d%d%s",&n,&k,s+1);
solve(k);
return 0;
}
\(E\)
为啥全世界都是按分解成全\(1\)数来做的……只有我是贪心的么……
事先声明我并不会证明这个贪心的正确性
贪心起见,我们每一次都选择把原数减去一个尽量大的数
假设这个数按数位可以写成\(a_1a_2a_3...a_n\),那么我们找到最大的\(p\),满足对于\(i<p\)都有\(a_i\leq a_{i+1}\)且\(a_{p-1}<a_p\),那么我们选择减去的数字就是\(a_1a_2...a_{p-1}(a_{p}-1)9...9\),也就是说前面那些加上后面若干个⑨。容易发现减去的数字必然合法且一定是最大的
然而我们显然不能高精减否则复杂度会炸掉……所以减去这个数字等价于把前\(p\)个数删掉并在后面加上\(1\),根据\(01\)计算器的原理如果加了\(n\)次\(1\),总复杂度是\(O(n)\)的,所以这一部分没问题
那么现在唯一的问题就是我们该如何找到这个\(p\)了,首先肯定不能暴力因为数据里有几个点专门卡掉了。我们发现合法的\(p\)必定是一段极长的连续相同数字的开头,那么我们用一个队列存储所有的合法的开头,每一次比较队头和队头的下一个元素,如果下一个元素更优那么直接把队头弹掉就好了,否则就找到了。这样的话每个数加入一次删除一次,或者因为\(+1\)的缘故而加入删除的话也是\(O(n)\),于是这一部分也是\(O(n)\)
综上总复杂度为\(O(n)\)
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e6+5;
char s[N];int a[N],q[N],h,t,n,res;
inline int min(R int x,R int y){return x<y?x:y;}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%s",s+1),n=strlen(s+1);
fp(i,1,n)a[i]=s[i]-'0';
a[n+1]=a[0]=23333;
h=1,t=0;
fp(i,1,n)if(a[i]!=a[i-1])q[++t]=i;
while(233){
++res,q[t+1]=n+1;
while(h<=t&&a[q[h+1]]>a[q[h]])++h;
if(h>t)break;
fd(i,n,q[h]+1){
if(a[i]==9){a[i]=0;continue;}
++a[i];
while(h<=t&&q[t]>=i)--t;
if(i==q[h]+1||a[i-1]!=a[i])q[++t]=i;
if(i+1<=n)q[++t]=i+1;
break;
}
++h;
if(q[h]!=q[h-1]+1)++q[h-1],--h;
while(h<=t&&!a[q[h]])++h;
if(h>t)break;
}
printf("%d\n",res);
return 0;
}
\(F\)
题目太神仙了我不看题解连题目都看不懂……
所以一起去膜拜大佬吧
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=5e5+5;
typedef long long ll;
struct node;typedef node* ptr;
struct node{
ptr lc,rc;int c;
inline void pd(){if(c)lc->c=c,rc->c=c,c=0;}
}e[N<<2],*pp=e,*rt;
ll s[N],dp[N],res;int a[N],b[N],l[N],r[N],st[N];
int n,P,m,top;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
void build(ptr &p,int l,int r){
p=++pp;if(l==r)return;
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
}
int query(ptr p,int l,int r,int x){
if(p->c||l==r)return p->c;
int mid=(l+r)>>1;
return x<=mid?query(p->lc,l,mid,x):query(p->rc,mid+1,r,x);
}
void update(ptr p,int l,int r,int ql,int qr,int v){
if(ql>qr)return;
if(ql<=l&&qr>=r)return p->c=v,void();
int mid=(l+r)>>1;p->pd();
if(ql<=mid)update(p->lc,l,mid,ql,qr,v);
if(qr>mid)update(p->rc,mid+1,r,ql,qr,v);
}
ll ask(R int x){
R int p=query(rt,1,top,x);
if(!p)return 0;
return dp[p]+dec(st[l[p]],st[x]);
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&P);
fp(i,1,n){
scanf("%d%d",&a[i],&b[i]),s[i]=s[i-1]+a[i];
if(b[i]==1&&(a[i]<<1)>P)return puts("-1"),0;
}
fd(i,n,1){
if(b[i]==1)l[i]=mul(s[i-1]%P,P-2),r[i]=mul(s[i]%P,P-2);
else l[i]=0,r[i]=P-1;
st[++top]=l[i],st[++top]=r[i];
}
sort(st+1,st+1+top),top=unique(st+1,st+1+top)-st-1;
build(rt,1,top);
fd(i,n,1){
l[i]=lower_bound(st+1,st+1+top,l[i])-st;
r[i]=lower_bound(st+1,st+1+top,r[i])-st;
dp[i]=ask(l[i]);
if(l[i]>r[i])update(rt,1,top,r[i]+1,l[i]-1,i);
else update(rt,1,top,1,l[i]-1,i),update(rt,1,top,r[i]+1,top,i);
}
res=dp[1];
fp(i,1,top)cmin(res,ask(i));
printf("%lld\n",res+(s[n]<<1));
return 0;
}
AtCoder Grand Contest 011题解的更多相关文章
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- AtCoder Grand Contest 017 题解
A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...
- AtCoder Grand Contest 011 F - Train Service Planning
题目传送门:https://agc011.contest.atcoder.jp/tasks/agc011_f 题目大意: 现有一条铁路,铁路分为\(1\sim n\)个区间和\(0\sim n\)个站 ...
- Atcoder Grand Contest 054 题解
那天晚上由于毕业晚会与同学吃饭喝酒没打 AGC,第二天稍微补了下题,目前补到了 E,显然 AGC 的 F 对于我来说都是不可做题就没补了(bushi A 简单题,不难发现如果我们通过三次及以上的操作将 ...
- AtCoder Grand Contest 030题解
第一次套刷AtCoder 体验良好 传送门 Poisonous Cookies cout<<b+min(c,a+b+); Tree Burning 难度跨度有点大啊 可以证明当第一次转向之 ...
- AtCoder Grand Contest 031题解
题面 传送门 题解 比赛的之后做完\(AB\)就开始发呆了--简直菜的一笔啊-- \(A - Colorful\ Subsequence\) 如果第\(i\)个字母选,那么它前面任意一个别的字母的选择 ...
- AtCoder Grand Contest 039 题解
传送门 \(A\) 首先只有一串的情况下,遇到相同的肯定是改后面那一个最优,然后两串的话可能要分奇偶讨论一下 //quming #include<bits/stdc++.h> #defin ...
- AtCoder Grand Contest 017题解
传送门 \(A\) 直接转移就是了 typedef long long ll; const int N=55; ll f[N][2];int a[N],n,p; int main(){ scanf(& ...
- AtCoder Grand Contest 015题解
传送门 \(A\) 找到能达到的最大的和最小的,那么中间任意一个都可以被表示出来 typedef long long ll; int n,a,b;ll res; int main(){ scanf(& ...
随机推荐
- java第三次面试总结
这次面试是二面,由于自己的经验不足,面试的结果不是很令人满意,所以与这家公司失之交臂,在这里记录一下经历,吸取教训. 之前的一面是笔试+面试,面试是主管,今天的面试是总监.在前台招待我的时候,还跟我说 ...
- 5_PHP数组_3_数组处理函数及其应用_8_数组与数据结构
以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. 数组与数据结构 1. array_push() 函数 程序: <?php $stack = array(&q ...
- 提高QPS
常用方案 1.异步化+MQ 即非阻塞,化繁为简,拿到你需要处理的资源后尽快回复.适用于事务处理场景,且无需对上游返回数据场景. 2.无锁设计 本质上是要降低锁冲突,基于数据版本的乐观锁 有效的减少了互 ...
- 【转载】C#使用Random类来生成指定范围内的随机数
C#的程序应用的开发中,可以使用Random随机数类的对象来生成相应的随机数,通过Random随机数对象生成随机数的时候,支持设置随机数的最小值和最大值,例如可以指定生成1到1000范围内的随机数.R ...
- MongoDB 4.2.1 安装失败,提示 verify that you have sufficient privileges to start system services 解决
官网下载地址:https://www.mongodb.com/download-center/community 问题: 解决:直接安装在根目录 测试:
- JavaScript 继承 封装 多态实现及原理详解
面向对象的三大特性 封装 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.封装是面向对象的特征之一,是对象和类概念的主要特性. ...
- hadoop2.8 集群 1 (伪分布式搭建)
简介: 关于完整分布式请参考: hadoop2.8 ha 集群搭建 [七台机器的集群] Hadoop:(hadoop2.8) Hadoop是一个由Apache基金会所开发的分布式系统基础架构.用户 ...
- MySQL小记——数据格式化
记录下今天在项目中出现的一个小问题. 将通过除运算获得的结果数据进行保留两位小数的处理时,我用了MySQL 的 FORMAT(X, D)函数,之前一直没有出现问题,但是由于周期性更新的数据库中突然出现 ...
- kubernetes集群的认证、授权、准入控制
一.kubernetes集群安全架构 用户使用kubectl.客户机或通过REST请求访问API.可以授权用户和Kubernetes服务帐户进行API访问.当一个请求到达API时,它会经历几个阶段,如 ...
- IP positioning check position
1.如何找到网上散布不法言论的人的地理位置 比方像微博发布的时候都会自动添加主机网络地址,需要对头文件进行分析 找到IP地址 然后进行反查IP地址的位置 , 如果是可以与要查的终端可以进行通信 ,可以 ...