ARC 122 简要题解

传送门

A - Many Formulae

考虑对于每个数分别算其贡献。

通过枚举该数前面的符号,借助一个非常简单的 \(\mathrm{DP}\)(\(f_{i,0/1}\) 表示 \(i\) 个符号,最后一个符号为 \(+/-\) 的方案数),我们可以很轻松的求出一个数对最终答案的贡献。

总时间复杂度为 \(O(n)\)。

/*---Author:HenryHuang---*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int p=1e9+7;
int dp[maxn][2];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;cin>>n;
dp[1][0]=dp[1][1]=1;
for(int i=2;i<n;++i){
dp[i][1]=dp[i-1][0];
dp[i][0]=(dp[i-1][0]+dp[i-1][1])%p;
}
int ans=0;
dp[0][0]=1;
for(int i=1;i<=n;++i){
int x;cin>>x;
ans=(ans-1ll*x*dp[i-1][1]%p*dp[n-i][0]%p+p)%p;
ans=(ans+1ll*x*dp[i-1][0]%p*(dp[n-i][0]+dp[n-i][1])%p)%p;
}
cout<<ans<<'\n';
return 0;
}

B - Insurance

猜想答案一定在某个数处取得,所以把所有数排序计算出所有的答案取个 \(\min\) 即可。

更为靠谱的做法的是,这个函数显然是个凸函数,你可以直接三分,你也可以直接排序过后取中位数的位置计算答案。

总时间复杂度为 \(O(n\log_2n)\),排序为复杂度瓶颈。

/*---Author:HenryHuang---*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll a[maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;cin>>n;
ll S=0;
for(int i=1;i<=n;++i){
cin>>a[i];
S+=a[i];
}
sort(a+1,a+n+1);
ll ans=(1ll<<60);
ll sum=0;
for(int i=1;i<=n;++i){
sum+=a[i];
ans=min(ans,n*a[i]+2*S-2*sum-2*(n-i)*a[i]);
}
cout<<setprecision(10)<<fixed<<(double)ans/2.0/n<<'\n';
return 0;
}

C - Calculator

注意到任意一个正整数 \(n\) 均可以表示为若干个斐波那契数的和。(证明大概可以数学归纳法,在此不再赘述)

然后原问题中 \(3,4\) 操作交替可以组成斐波那契数,然后斐波那契数可以一起递推。

然后随便搞搞就行了,注意一些可能的细节,例如可能递推到最后某一项落在 \(y\) 上需要特殊处理。


还有一种方法,你大概可以找到 \(\phi \times n\),其中 \(\phi\) 是黄金分割比。然后令 \(x=n,y=\phi \times n\),倒着做,处理一些必要的边界即可。

/*---Author:HenryHuang---*/
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll f[100];
vector<int> ans;
int flag[100],tag[100];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll n;cin>>n;
f[0]=f[1]=1;
for(int i=2;i<=88;++i) f[i]=f[i-1]+f[i-2];
for(int i=88;i>=1;--i){
if(n>=f[i]) n-=f[i],ans.emplace_back(i);
}
int now=ans[0],tim=0;
for(auto x:ans){
if((now&1)==(x&1)){
tag[x]=1;
flag[x]=1;
}
else{
tag[x+1]=2;
flag[x+1]=1;
}
}
ll x=0,y=0;
vector<int> Ans;
if(now&1) Ans.emplace_back(2),Ans.emplace_back(3),tim=1;
else Ans.emplace_back(1),Ans.emplace_back(4),tim=0;
for(int i=now-1;i>=1;--i){
if(flag[i]){
if(tag[i]==1){
if(tim==1) Ans.emplace_back(1);
else Ans.emplace_back(2);
}
else{
if(tim==1) Ans.emplace_back(2);
else Ans.emplace_back(1);
}
}
if(tim==1) Ans.emplace_back(4);
else Ans.emplace_back(3);
tim^=1;
}
cout<<Ans.size()<<'\n';
for(auto u:Ans){
cout<<u<<'\n';
if(u==1) ++x;
if(u==2) ++y;
if(u==3) x=x+y;
if(u==4) y=x+y;
}
// cout<<x<<' '<<y<<'\n';
return 0;
}

D - XOR Game

注意到如果存在一对完美匹配,使得每对匹配的数的异或的最大值为 \(x\),那么一定可以构造一组解使得最终答案为 \(x\)。

构造显然,按照匹配构造即可。

所以 Alice 在这个游戏里没啥用,全看 Bob 操作

所以现在问题转化为了找一对完美匹配,使得每对匹配的数的异或的最大值最小。

我们从高位到低位考虑。

  • 若当前位置 \(0\) 的个数和 \(1\) 的个数均为偶数个,那么我们可以将其内部两两匹配使得答案在这一位上全部为 \(0\),分开递归继续计算即可。
  • 否则我们只需要在对于每一个当前位置为 \(0\) 的数,求出其与当前位置为 \(1\) 的数的异或的最小值即可。注意到此时我们并不需要递归继续计算,因为其他位置对答案的贡献在这一位上都是 \(0\),一定比我们求出的这个异或的最小值更小。

然后做完了。

总时间复杂度为 \(O(n\log_2\max{a_i})\)。

/*---Author:HenryHuang---*/
/*---Never Settle---*/
/*---Never Enough---*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
struct TRIE{
int ch[maxn*30][2],cnt,rt;
void clear(){
for(int i=0;i<=cnt;++i) ch[i][0]=ch[i][1]=0;
cnt=rt=0;
}
void insert(int x){
int now=rt;
for(int i=29;i>=0;--i){
int v=((x&(1<<i))!=0);
if(!ch[now][v]) ch[now][v]=++cnt;
now=ch[now][v];
}
}
int query(int x){
int now=rt;
int ans=0;
for(int i=29;i>=0;--i){
int v=((x&(1<<i))!=0);
if(ch[now][v]) now=ch[now][v];
else now=ch[now][v^1],ans+=(1<<i);
}
return ans;
}
}trie;
int solve(vector<int> a,int bit){
if(bit==-1||a.size()==0) return 0;
vector<int> zero,one;
for(auto x:a){
if(x&(1<<bit)) one.emplace_back(x);
else zero.emplace_back(x);
}
if(zero.size()%2==0)
return max(solve(zero,bit-1),solve(one,bit-1));
else{
trie.clear();
for(auto x:zero) trie.insert(x);
int ans=(1<<30);
for(auto x:one) ans=min(ans,trie.query(x));
return ans;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;cin>>n;
n<<=1;
vector<int> v;
for(int i=1;i<=n;++i){
int x;cin>>x;
v.emplace_back(x);
}
cout<<solve(v,29)<<'\n';
return 0;
}

E - Increasing LCMs

一个数 \(a_i\) 能够作为重排过后的最后一个数,当且仅当前面数的 \(\mathrm{lcm}\) 不是其倍数。

形式化的,即 \(\gcd(\mathrm{lcm}_{j\neq i}\{a_j\},a_i)<a_i\)。

稍微变形一下,可以得到 \(\mathrm{lcm}_{j\neq i}\{\gcd(a_j,a_i)\}<a_i\)。

按照这个式子暴力模拟递归做就行了。

时间复杂度为 \(O(n^3\log_2\max a_i)\)。

/*---Author:HenryHuang---*/
/*---Never Settle---*/
/*---Never Enough---*/
#include<bits/stdc++.h>
#define eps 1e-6
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){
if(!b) return a;
return gcd(b,a%b);
}
vector<ll> ans;
void solve(vector<ll> a){
if(a.size()==1){
ans.emplace_back(a[0]);
return ;
}
for(int i=0;i<a.size();++i){
int flag=1;
ll lcm=1;
for(int j=0;j<a.size();++j){
if(j==i) continue;
ll owo=gcd(a[j],a[i]);
ll qaq=gcd(lcm,owo);
if(log(a[i])-log(lcm/qaq)-log(owo)>eps){
lcm=lcm/qaq*owo;
}
else{
flag=0;
break;
}
}
if(flag){
ans.emplace_back(a[i]);
vector<ll> tmp;
for(int j=0;j<a.size();++j){
if(j==i) continue;
tmp.emplace_back(a[j]);
}
solve(tmp);
break;
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;cin>>n;
vector<ll> v;
for(int i=1;i<=n;++i){
ll x;cin>>x;
v.emplace_back(x);
}
solve(v);
if(ans.size()!=n) cout<<"No\n";
else{
cout<<"Yes\n";
reverse(ans.begin(),ans.end());
for(auto x:ans) cout<<x<<' ';
cout<<'\n';
}
return 0;
}

F - Domination

场上没人过的神题。

首先注意到如果两个红点 \((x_i,y_i),(x_j,y_j)\),如果 \(x_i\le x_j,y_i\le y_j\),那么显然不需要考虑 \((x_i,y_i)\) 这个点,因为 \((x_j,y_j)\) 的限制显然更为严格。

那么所有的红点会自左上到右下大约排成一行,将其按照左上到右下编号。

然后有一个比较显然的转化:

每个红点右上有 \(k\) 个蓝点,等价于将这些蓝点分成 \(k\) 组,使得每组蓝点覆盖所有红点。

假设 \(k=1\)。

考虑如果一个蓝点要覆盖 \([l,r]\) 这个区间内的所有红点,那么他的坐标 \((X,Y)\) 应该满足 \(X\ge x_r,Y\ge y_l\)。

也就是说,如果一个蓝点原来的位置为 \((bx,by)\),其覆盖 \([l,r]\) 的代价为 \(\max(0,x_r-bx)+\max(0,y_l-by)\)。

我们可以考虑构造这样的一个坐标系:

在 \(y\) 轴上往下走一单位有 \(1\) 的代价,在 \(x\) 轴上往右走有 \(1\) 的代价。

然后在 \(by\) 与 \(bx\) 之间连一条代价为 \(0\) 的边。

则最后覆盖 \([l,r]\) 这个区间的代价就是 \(y_l\) 到 \(x_r\) 的最短路。

推广到覆盖 \([1,n]\) 的情况是类似的。

若 \(k\) 更大,问题就转化为了一个最小费用流问题。

时间复杂度为 \(O(k(n+m)\log_2(n+m))\)。

/*---Author:HenryHuang---*/
/*---Never Settle---*/
/*---Never Enough---*/
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int maxn=5e5+5;
typedef long long ll;
int n,m,s,t,k;
vector<pair<int,int> > R,B;
vector<int> X,Y;
struct edge{
int to,nex,w,v;
}e[maxn*30];
int head[maxn],cur[maxn],cnt=1;
void add(int a,int b,int c,int d){
e[++cnt]=(edge){b,head[a],c,d};
head[a]=cnt;
}
void addedge(int a,int b,int c,int d){
add(a,b,c,d),add(b,a,0,-d);
}
int vis[maxn],vi[maxn];
ll flow,cost;
ll dis[maxn],h[maxn];
bool DJ(){
for(int i=0;i<=t;++i) dis[i]=(1ll<<60),cur[i]=head[i],vi[i]=0;
priority_queue<pair<ll,int> > Q;
dis[t]=0;
Q.emplace(-dis[t],t);
while(!Q.empty()){
ll d;int u;tie(d,u)=Q.top();Q.pop();
if(vi[u]) continue;
vi[u]=1;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
if(e[i^1].w&&dis[v]>dis[u]+h[u]-h[v]+e[i^1].v){
dis[v]=dis[u]+h[u]-h[v]+e[i^1].v;
Q.emplace(-dis[v],v);
}
}
}
for(int i=0;i<=t;++i) if(dis[i]<(1ll<<60)) h[i]+=dis[i];
return dis[s]<(1ll<<60);
}
int dfs(int u,int in){
if(u==t) return in;
int out=0,tmp;
vis[u]=1;
for(int &i=cur[u];i;i=e[i].nex){
int v=e[i].to;
if((!vis[v])&&e[i].w&&h[v]-h[u]+e[i].v==0&&(tmp=dfs(v,min(in,e[i].w)))){
e[i].w-=tmp,e[i^1].w+=tmp;
in-=tmp,out+=tmp;
if(!in) break;
}
}
if(!out) dis[u]=0;
vis[u]=0;
return out;
}
void MCMF(){
while(DJ()){
ll tmp=dfs(s,inf);
flow+=tmp,cost+=tmp*h[s];
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;++i){
int x,y;cin>>x>>y;
R.emplace_back(x,y);
}
for(int i=1;i<=m;++i){
int x,y;cin>>x>>y;
B.emplace_back(x,y);
}
sort(R.begin(),R.end());
int now=0;
for(int i=0;i<n;++i){
while(now&&R[now-1].second<=R[i].second) --now;
R[now]=R[i];++now;
}
n=now;R.resize(n);
for(auto u:R){
X.emplace_back(u.first);
Y.emplace_back(u.second);
}
for(auto u:B){
X.emplace_back(u.first);
Y.emplace_back(u.second);
}
sort(X.begin(),X.end());
sort(Y.begin(),Y.end());
X.erase(unique(X.begin(),X.end()),X.end());
Y.erase(unique(Y.begin(),Y.end()),Y.end());
int sx=X.size(),sy=Y.size();
s=sx+sy+1,t=sx+sy+2;
for(int i=0;i<sx-1;++i){
addedge(i,i+1,inf,X[i+1]-X[i]);
addedge(i+1,i,inf,0);
}
for(int i=0;i<sy-1;++i){
addedge(sx+i+1,sx+i,inf,Y[i+1]-Y[i]);
addedge(sx+i,sx+i+1,inf,0);
}
for(auto &u:R){
u.first=lower_bound(X.begin(),X.end(),u.first)-X.begin();
u.second=lower_bound(Y.begin(),Y.end(),u.second)-Y.begin();
}
for(auto &u:B){
u.first=lower_bound(X.begin(),X.end(),u.first)-X.begin();
u.second=lower_bound(Y.begin(),Y.end(),u.second)-Y.begin();
}
for(int i=0;i<n-1;++i)
addedge(R[i].first,R[i+1].second+sx,inf,0);
addedge(s,R[0].second+sx,k,0);
addedge(R[n-1].first,t,k,0);
for(auto u:B){
int x,y;tie(x,y)=u;
addedge(y+sx,x,1,0);
}
MCMF();
cout<<cost<<'\n';
return 0;
}

ARC 122 简要题解的更多相关文章

  1. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  2. 【题解】Comet OJ 国庆欢乐赛 简要题解

    [题解]Comet OJ 国庆欢乐赛 简要题解 A 直接做 B 直接做,结论: \[ ans=\max([Max\ge \mathrm{sum}] Max,s[n]/2) \] C 考虑这样一个做法: ...

  3. Noip 2014酱油记+简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  4. Tsinghua 2018 DSA PA2简要题解

    反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...

  5. Codeforces 863 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...

  6. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

  7. JXOI2018简要题解

    JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...

  8. BJOI2018简要题解

    BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...

  9. CQOI2018简要题解

    CQOI2018简要题解 D1T1 破解 D-H 协议 题意 Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法.它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信 ...

随机推荐

  1. Python+Selenium学习笔记2 - 字符串

    跟着网络课程学了几个小程序. 1.判断a字符串是否为b字符串的子串 1 # coding = utf-8 2 3 # 判断str_a字符串是否为str_b字符串的子串 4 5 str_a = &quo ...

  2. TVM性能评估分析(七)

    TVM性能评估分析(七) Figure 1.  Performance Improvement Figure 2.  Depthwise convolution Figure 3.  Data Fus ...

  3. TensorFlow实现多层感知机函数逼近

    TensorFlow实现多层感知机函数逼近 准备工作 对于函数逼近,这里的损失函数是 MSE.输入应该归一化,隐藏层是 ReLU,输出层最好是 Sigmoid. 下面是如何使用 MLP 进行函数逼近的 ...

  4. 孟老板 BaseAdapter封装(五) ListAdapter

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  5. Java基础_循环嵌套_打印乘法口诀、菱形,各种图形,计算二元一次和三元一次方程组_7

    循环嵌套 打印乘法口诀 for(int j=1;j<=9;j++){ for(int i=1;i<=j;i++){ System.out.print(i+"*"+j+& ...

  6. 在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test)

      本文是在模仿中精进数据分析与可视化系列的第一期--颗粒物浓度时空变化趋势(Mann–Kendall Test),主要目的是参考其他作品模仿学习进而提高数据分析与可视化的能力,如果有问题和建议,欢迎 ...

  7. 技能篇:awk教程-linux命令

    前言 AWK是一门解释型的编程语言.用于文本处理,它的名字来源于它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan awk 程序结构 运行 ...

  8. Windows下Django的安装与项目创建

    1.Django的安装命令:pip install django 2.如果要指定安装版本可用:pip install django==1.10.3 3.查看指定的安装库:pip show django ...

  9. linux安装后配置

    1.1 系统设置(自测用,公司不需要) 1.1.1 Selinux系统安全保护 Security-Enhanced Linux – 美国NSA国家安全局主导开发,一套增强Linux系统安 全的强制访问 ...

  10. 【NX二次开发】缝合片体例子UF_MODL_create_sew

    缝合片体,没有成功缝合的片体涂绿色. 效果:  源码: extern DllExport void ufusr(char *param, int *returnCode, int rlen) { UF ...