点我看题

A - Max Mod Min

非常诈骗。一开始以为要观察什么神奇的性质,后来发现直接模拟就行了。可以证明总操作次数是\(O(nlog a_i)\)的。具体就是,每次操作都会有一个数a被b取模,然后变成a%b。注意到a%b是\(\leq \frac a2\)的,并且a被操作之后会变成整个数据最小的数,作为下一轮的b。所以把原数组排序后,最小值的位置是不断往左移的,每次移动1个位置,直接模拟即可。

时间复杂度\(O(nlog a_i)\)。

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair using namespace std; int n,a[200010];
multiset <int> st; int main()
{
cin>>n;
rep(i,n) scanf("%d",&a[i]),st.insert(-a[i]);
int ans=0;
while(st.size()>1)
{
int val=-*st.begin(),dv=-*st.rbegin();
st.erase(st.begin());
val%=dv;
if(val>0) st.insert(-val);
++ans;
}
cout<<ans<<endl;
return 0;
}

B - Swap to Sort

数值分成2类,奇数应在奇数位置,偶数应在偶数位置。但是初始会有一些奇数在偶数位置,也会有一些偶数在奇数位置。容易发现这两类数的个数是相等的,令其中一类的个数为k。A类操作的作用就是把一个奇数位置的偶数和一个偶数位置的奇数交换。发现只要k次A操作就可以让所有奇数在奇数位置,偶数在偶数位置,完成这一步后对所有奇数位置/所有偶数位置分别用B操作冒泡排序即可,一共40000次操作左右;且这k次A操作不可缺少。其他工作都可以用B操作完成。让所有奇数在奇数位置,偶数在偶数位置的具体做法是:先随便找一个在偶数位置的奇数,再随便找一个奇数位置的偶数,用B操作把它们换到相邻,然后一次A即可,一共40000次左右。这样总操作数不会超过100000。

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair using namespace std; int n,p[410];
vector <pii> ans; void swpA(int i)
{
swap(p[i],p[i+1]);
ans.pb(mpr(0,i));
}
void swpB(int i)
{
swap(p[i],p[i+2]);
ans.pb(mpr(1,i));
} void isort(int w)
{
vector <int> poss;
repn(i,n) if(i%2==w) poss.pb(i);
while(true)
{
bool hv=false;
rep(i,poss.size()-1) if(p[poss[i]]>p[poss[i+1]])
{
swpB(poss[i]);
hv=true;break;
}
if(!hv) break;
}
} int main()
{
cin>>n;
repn(i,n) cin>>p[i];
while(true)
{
bool hv=false;
repn(i,n) if(i%2==0&&p[i]%2==1)
{
int to=-1;
repn(j,n) if(j%2==1&&p[j]%2==0) to=j;
if(to>i)
{
int stp=(to-i)/2,cur=i;
rep(j,stp)
{
swpB(cur);
cur+=2;
}
swpA(cur);
}
else
{
int stp=(i-to)/2,cur=i;
rep(j,stp)
{
swpB(cur-2);
cur-=2;
}
swpA(cur-1);
}
hv=true;break;
}
if(!hv) break;
}
isort(0);isort(1);
cout<<ans.size()<<endl;
rep(i,ans.size())
{
if(ans[i].fi==0) printf("A ");
else printf("B ");
printf("%d\n",ans[i].se);
}
return 0;
}

C - Min Diff Sum

考虑最终选出的所有位置,从小到大排序,令第\(\lfloor \frac n2 \rfloor\)个为x。则排序时排在x左边,且其位置的值\(<x\)的变量如果能往右移哪怕1个位置,也是好的,但是为什么不能移,因为它已经在对应线段的右端点了。排序时排在x右边的同理。这启发我们可以枚举所在的区间。把所有\(l_i\)和\(r_i\)排序并去重,枚举排好的序列中相邻的2个位置\(a,b\),计算\(a \leq x \leq b\)时的最优答案。找出所有\(r_i < a\)的线段,它们对应的值只能选\(r_i\),令这样的线段有ca个。所有\(l_i > b\)的只能选\(l_i\),令这样的线段有cb个。其他的显然是选与x相同最好。如果\(ca \geq cb\),显然x选a比较好,否则x选b比较好。记录几个部分的线段数量、端点位置之和等信息即可\(O(1)\)计算。

时间复杂度\(O(nlogn)\)。

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <LL,LL>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair using namespace std; LL n,l[300010],r[300010],lsum=0,rsum=0,lcnt=0,rcnt=0,stat[300010],ans=LONG_LONG_MAX;
vector <pair <LL,pii> > op;
vector <LL> L; int main()
{
cin>>n;
LL addi=0;
rep(i,n)
{
scanf("%lld%lld",&l[i],&r[i]);
op.pb(mpr(l[i],mpr(-1,i)));op.pb(mpr(r[i],mpr(1,i)));
stat[i]=1;
L.pb(l[i]);
}
sort(L.begin(),L.end());
rep(i,L.size())
{
addi+=L[i]*rcnt-rsum;
rsum+=L[i];++rcnt;
} sort(op.begin(),op.end());
rep(i,op.size()-1)
{
if(op[i].se.fi==-1)
{
stat[op[i].se.se]=0;
--rcnt;rsum-=l[op[i].se.se];
addi-=rsum-l[op[i].se.se]*rcnt;
}
else
{
stat[op[i].se.se]=1;
addi+=r[op[i].se.se]*lcnt-lsum;
++lcnt;lsum+=r[op[i].se.se];
}
LL lb=op[i].fi,ub=op[i+1].fi,mid=n-lcnt-rcnt,act=(lcnt>=rcnt ? lb:ub);
LL res=0;
res+=act*(mid+rcnt)*lcnt-lsum*(mid+rcnt);
res+=rsum*(mid+lcnt)-act*(mid+lcnt)*rcnt;
ans=min(ans,res+addi);
//cout<<lb<<' '<<ub<<' '<<lcnt<<' '<<rcnt<<' '<<res<<' '<<lsum<<' '<<rsum<<' '<<act<<endl;
}
cout<<ans<<endl;
return 0;
}

D - Sets Scores

出这种代码只有1行的数学诈骗题有意思吗.jpg

atcoder出题真是越来越魔怔了,arc出屑题,abc出大量板子题

n个集合,会有n+1个空隙(包括头尾)。如果第i和第i+1个集合中有一个不同的元素x,就在它们两个集合之间的空隙中填上一个编号为x的标记。同时,把1号集合中含有的元素对应的标记都填到它前面的空隙中。n号集合同理,填到它后面的空隙中。注意到每种标记都有偶数个。题目中的要求等价于每两个相邻集合中间的空隙用有恰好1个标记,首尾空隙任意。题目要求的是\(\sum\prod_i i在所有集合中出现的次数总和\),它等价于我们枚举m个集合\(t_1 \cdots t_m\),表示要求\(i在t_i\)中出现,求出满足这个条件的填标记方案数,并对所有枚举方式求和。对于某种填标记方案,i在\(t_i\)中出现当且仅当\(t_i\)前面有奇数个i号标记。乍一看很难判断,但是其实我们只要确定哪些中间空隙(不包括首尾)含有i号标记,再确定\(t_i\),首尾空隙中是否有i号标记就已经确定了,因为别忘了每种标记都有偶数个。所以可以先枚举所有\(t_i\),方案数\(n^m\);再枚举每个中间空隙填了哪种类型的标记,方案数\(m^{n-1}\),两个乘起来即可。

时间复杂度\(O(logn+logm)\)。

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair using namespace std; const LL MOD=998244353; LL qpow(LL x,LL a)
{
LL res=x,ret=1;
while(a>0)
{
if((a&1)==1) ret=ret*res%MOD;
a>>=1;
res=res*res%MOD;
}
return ret;
} LL n,m; int main()
{
cin>>n>>m;
LL ans=qpow(m,n-1);
(ans*=qpow(n,m))%=MOD;
cout<<ans<<endl;
return 0;
}

E - Examination

还是挺妙的,场上有100多个人切了,后来果然发现有原题

判无解的方法大家肯定都会了,把a和b分别从小到大排序,如果有一位\(a_i < b_i\)就无解。

有解的情况,我们考虑找出一个集合,它里面的元素可能会互相交换分数;剩下的元素分数都不变,自给自足,并给答案贡献1,最优解显然可以通过找出一个最小的合法集合来确定。

显然,所有\(a_i < b_i\)的人都在这个集合里;所有\(a_i=b_i\)的人都不在这个集合里,因为它们如果在集合里,最低要求就是他自己本身已有的分数,什么贡献都不能有,还可能会侵占资源。其他\(a_i > b_i\)的,可以考虑把它们一个一个加入集合中,使得集合合法;同时也要使加入的元素尽量少。分析一下集合s合法的条件,其实是:对于任意i,满足\(\sum_j^{|s|} [b_j<i]-[a_j<i]\)。证明也比较显然,这样每一个\(a_i\)都能在他前面找到一个\(b_i\)与其匹配;不满足这个条件则不行。一开始集合中有所有\(a_i<b_i\)的人,考虑贪心向其中添加一些元素,使得其合法,且添加的元素最少。我们每次找到最小的i使得i不满足上面那个式子的条件。显然,我们需要一个\(b_j \leq i,a_j > i\)的元素来救。发现\(b_i\)的大小是无关紧要的,因为i之前的位置都已经满足上面式子的条件。所以我们肯定应该选择\(a_j\)最大的j添加。实现的话,从小到大把所有i扫描一遍即可,用一个优先队列维护可以加入集合的元素。代码很好写,具体实现可以看代码。

时间复杂度:\(O(nlogn)\)。

点击查看代码
#include <bits/stdc++.h>

#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define pb push_back
#define fi first
#define se second
#define mpr make_pair using namespace std; int n,a[300010],b[300010],mp[600010],ans=0;
vector <int> as,bs,dsc,add[600010];
priority_queue <int> q; int main()
{
cin>>n;
rep(i,n)
{
scanf("%d%d",&a[i],&b[i]);
as.pb(a[i]);bs.pb(b[i]);
dsc.pb(a[i]);dsc.pb(b[i]);
}
sort(as.begin(),as.end());sort(bs.begin(),bs.end());
rep(i,n)
{
if(as[i]<bs[i])
{
puts("-1");
return 0;
}
}
sort(dsc.begin(),dsc.end());dsc.erase(unique(dsc.begin(),dsc.end()),dsc.end());
rep(i,n)
{
a[i]=lower_bound(dsc.begin(),dsc.end(),a[i])-dsc.begin();
b[i]=lower_bound(dsc.begin(),dsc.end(),b[i])-dsc.begin();
if(a[i]<b[i]) --mp[a[i]],++mp[b[i]];
else if(a[i]>b[i]) add[b[i]].pb(i);
else ++ans;
}
int sum=0;
rep(i,dsc.size())
{
sum+=mp[i];
rep(j,add[i].size()) q.push(a[add[i][j]]);
while(sum<0)
{
int f=q.top();q.pop();
++sum;--mp[f];
}
}
ans+=q.size();
cout<<ans<<endl;
return 0;
}

[题解] Atcoder Regular Contest ARC 147 A B C D E 题解的更多相关文章

  1. [题解] Atcoder Regular Contest ARC 151 A B C D E 题解

    点我看题 昨天刚打的ARC,题目质量还是不错的. A - Equal Hamming Distances 对于一个位置i,如果\(S_i=T_i\),那么不管\(U\)的这个位置填什么,对到\(S\) ...

  2. [题解] Atcoder Regular Contest ARC 148 A B C E 题解

    点我看题 题目质量一言难尽(至少对我来说 所以我不写D的题解了 A - mod M 发现如果把M选成2,就可以把答案压到至多2.所以答案只能是1或2,只要判断答案能不能是1即可.如果答案是1,那么M必 ...

  3. [题解] Atcoder Regular Contest ARC 146 A B C D 题解

    点我看题 A - Three Cards 先把所有数按位数从多到少排序,答案的位数一定等于位数最多的三个数的位数之和\(tot\).对于每个i,把有i位的数排序,并记录每个i的排序结果.最后枚举答案中 ...

  4. AtCoder Regular Contest 094 (ARC094) CDE题解

    原文链接http://www.cnblogs.com/zhouzhendong/p/8735114.html $AtCoder\ Regular\ Contest\ 094(ARC094)\ CDE$ ...

  5. AtCoder Regular Contest 096

    AtCoder Regular Contest 096 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个 ...

  6. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  7. AtCoder Regular Contest 092

    AtCoder Regular Contest 092 C - 2D Plane 2N Points 题意: 二维平面上给了\(2N\)个点,其中\(N\)个是\(A\)类点,\(N\)个是\(B\) ...

  8. AtCoder Regular Contest 093

    AtCoder Regular Contest 093 C - Traveling Plan 题意: 给定n个点,求出删去i号点时,按顺序从起点到一号点走到n号点最后回到起点所走的路程是多少. \(n ...

  9. AtCoder Regular Contest 094

    AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几 ...

随机推荐

  1. 【学习笔记】带你从0开始学习 01Trie

    01Trie Section 1:普通 Trie Section 1.1 什么是 Trie Trie 树,即字典树,是一种树形结构.典型应用是用于统计和排序大量的字符串前缀来减少查询时间,最大限度地减 ...

  2. K阶斐波那契数列--------西工大NOJ习题.10

    K阶斐波那契数列--------西工大NOJ习题.10 原创不易,转载请说明出处!!! 科普:k阶斐波那契数列的0到n-1项需要有初始值. 其中,0到n-2项初始化为0,第n-1项初始化为1. 在这道 ...

  3. 【Azure Developer】在Azure VM (Windows) 中搭建 kafka服务,并且通过本地以及远程验证 发送+消费 消息

    问题描述 查看了 "How to Install and Run Apache Kafka on Windows? " 一文后,成功安装了Kafka服务,但是如何使用呢?如何在其他 ...

  4. Modbus转OPC

    在这里给大家介绍一种低成本的将Modbus RTU协议的串口设备接入到OPC UA的服务器呢? OPC全称是OLE(Object Linking and Embedding) for Process ...

  5. 基于python3.7利用Motor来异步读写Mongodb提高效率

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_111 如果使用Python做大型海量数据批量任务时,并且backend用mongodb做数据储存时,常常面临大量读写数据库的情况. ...

  6. Blazor和Vue对比学习(进阶2.2.4):状态管理之持久化保存(2),Cookie/Session/jwt

    注:本节涉及到前后端,这个系列的对比学习,还是专注在前端Vue和Blazor技术,所以就不撸码了,下面主要学习概念. 我们知道,Http是无状态协议,客户端请求服务端,认证一次后,如果再次请求,又要重 ...

  7. 项目操作案例丨西门子PLC通过网关连接ACS800变频器

    本案例控制对象为炉条机.以及蒸汽的控制以及现场数据参数的显示以及报警. PLC 选用西门子 CPU,通过 ET200 IO 模块控制现场设备并监控数据.变频器采用ABB ACS800变频器,将ABB ...

  8. 从 Airflow 到 Apache DolphinScheduler,有赞大数据开发平台的调度系统演进

    点击上方 蓝字关注我们 作者 | 宋哲琦 ✎ 编 者 按 在不久前的 Apache  DolphinScheduler Meetup 2021 上,有赞大数据开发平台负责人 宋哲琦 带来了平台调度系统 ...

  9. Luogu4391 [BOI2009]Radio Transmission 无线传输 (KMP)

    \(最小循环节\) \(=\) \(lenghth - next[lenghth]\) #include <iostream> #include <cstdio> #inclu ...

  10. Java SE 9 多版本兼容 JAR 包示例

    Java SE 9 多版本兼容 JAR 包示例 作者:Grey 原文地址:Java SE 9 多版本兼容 JAR 包示例 说明 Java 9 版本中增强了Jar 包多版本字节码文件格式支持,也就是说在 ...