点我看题

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. vue使用vuex报错 "export 'watch' was not found in 'vue'

    问题 安装Vuex后报错"export 'watch' was not found in 'vue' 解决方法 如果你的vue版本是 2.X ,将vuex升到 3.X.X 就能够解决 npm ...

  2. input函数的高级使用

    经典的a+b问题终于重出江湖了 a=input('a = ') b=input('b = ') print(a+b)//error,因为此时ab是字符串类型,其加号起到的是连接的作用 所以这就是类型转 ...

  3. YII服务定位器依赖注入

    <?php /** * Created by PhpStorm. * Date: 2016/5/25 * Time: 18:33 * 服务定位器依赖注入 */ namespace fronten ...

  4. 举重若轻流水行云,前端纯CSS3实现质感非凡的图片Logo鼠标悬停(hover)光泽一闪而过的光影特效

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_197 喜欢看电影的朋友肯定会注意到一个有趣的细节,就是电影出品方一定会在片头的Logo环节做一个小特效:暗影流动之间光泽一闪而过, ...

  5. 虚言妙诀终虚见,面试躬行是致知,Python技术面试策略与技巧实战记录

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_183 2021年,对于正在找工作的朋友来说,笼罩在新冠肺炎疫情之下,今年的就业季显得更加具有挑战性,更有意思的是,每当这个时候,各 ...

  6. 学python,怎么能不学习scrapy呢!

    摘要:本文讲述如何编写scrapy爬虫. 本文分享自华为云社区<学python,怎么能不学习scrapy呢,这篇博客带你学会它>,作者: 梦想橡皮擦 . 在正式编写爬虫案例前,先对 scr ...

  7. selenium结合jmeter进行测试

    背景 现在市面上有众多成熟的性能测试工具,JMeter就是其中之一.可以通过JMeter快速将已有的Selenium代码以性能测试的方式组织起来,并使用JMeter丰富的报表功能展示测试结果. 相关链 ...

  8. PyCharm 2022.2 发布了,支持最新 Python 3.11 和 PyScript 框架!

    来源:Jet Brains官网:翻译:Python猫 原文:https://blog.jetbrains.com/pycharm/2022/07/2022-2 通常而言,使用新潮的或者快速发展的技术, ...

  9. 前端React项目遇到【Uncaught SyntaxError: Unexpected token '<'】错误的解决方式

    问题描述 前端部署好项目后,打开相应的页面显示一片空白,打开console显示 问题排查思路 理解问题的本质 出现这个错误的原因是浏览器期望得到js文件,但页面却返回了html文件,如图中的js文件点 ...

  10. 图床搭建|chrome插件|操作简单不要钱

    为什么需要一个图床 为了写博客 图床:专门用来存放图片,同时允许你把图片对外连接的网上空间. 用markdown格式写作,插入图片需要图片的url地址,然后博客的背景图也是要用url地址. 有段时间, ...