点我看题

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. SpringBoot集成文件 - 集成POI之Excel导入导出

    Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能.本文主要介绍通过Spr ...

  2. DongDong认亲戚 来源:牛客网

    题目 链接:https://ac.nowcoder.com/acm/contest/28886/1021 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K, ...

  3. php date函数和首位带0问题

    一.带零 echo date('Y-m-d'); 2012-08-08 二.不带零 echo date('Y-n-j'); 2012-8-8 以下为参数详解(转载): a - "am&quo ...

  4. 关于微信小程序生产环境体验版获取不到openId的问题(大坑)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_119 我们知道openid是微信用户验证的重要标识,支付功能严重依赖这个东西,之前我们做微信支付的时候是通过在微信客户端直接调用官 ...

  5. HTTP配置

    目录 HTTP配置 虚拟主机 相同IP不同端口 不同IP相同端口 相同IP相同端口不同域名 Linux修改hosts文件 Windows修改hosts文件 配置https HTTP配置 虚拟主机 虚拟 ...

  6. 使用Fiddler劫持网络资源为前端开发助力(示例:Dynamic CRM 表单开发 也能热更新? )

    背景: 使用过vue开发的童鞋应该都知道,在开发vue项目的过程中,有个叫"热更新"的功能特别爽,在传统html开发到初次接触vue时,才发现原来前端开发可以这么香.热更新的表现形 ...

  7. hotspot算法实现 <<深入理解Java虚拟机>>

    1.枚举根节点 解决何时枚举,不需要实时的枚举,oopMap数据结构对象存储枚举信息 对象引用发生变化,需要存储每一条指令到OOPMap吗,,几百M的对象耗时需要很大的内存.GC空间成本 2.安全点: ...

  8. 【MySQL】从入门到精通8-SQL数据库编程

    上期:[MySQL]从入门到精通7-设计多对多数据库 第零章:Mac用户看这里: mac终端写MySQL和windows基本相同,除了配置环境变量和启动有些许不同以外. 先配置环境变量,在终端输入vi ...

  9. 面试突击78:@Autowired 和 @Resource 有什么区别?

    @Autowired 和 @Resource 都是 Spring/Spring Boot 项目中,用来进行依赖注入的注解.它们都提供了将依赖对象注入到当前对象的功能,但二者却有众多不同,并且这也是常见 ...

  10. C#使用Spire.Pdf包对PDF文档进行数字签名

    背景 对PDF文档进行数字签名的需求 对PDF文档添加水印的需求 网上资料版本不一或不全 本文章提到的Spire.Pdf均是使用的Spire.Pdf for .NET,除此之前还有其他语言的版本,如S ...