当前位置: 代码迷 >> 综合 >> M-SOLUTIONS Programming Contest 2020 Solution
  详细解决方案

M-SOLUTIONS Programming Contest 2020 Solution

热度:23   发布时间:2024-02-01 08:12:24.0

文章目录

  • 前言
  • A A
  • B B
  • C C
  • D D
  • E E
  • F F

前言

第一次perf打满,好激动.

A A

显然相邻段位的上下界差200.
然后…

int n; qr(n);
pr2((1999-n)/200+1);

B B

已知 a , b , c , k a,b,c,k .
你现在有 k k 次操作,每次使得一个数乘2.
问最后可不可能 c > b > a c>b>a .

简单贪心.先让 b > a b>a ,再让 c > b c>b .

int main() {int a,b,c; qr(a); qr(b); qr(c);int n; qr(n);bool ans=1;while(n--) {if(b<=a) b*=2;else c*=2;}if(c>b&&b>a) puts("Yes");else puts("No");return 0;
}

C C

相邻两个的成绩有 k ? 1 k-1 个公共部分,比较不同的两个即可.

int n,m,a[N];int main() {qr(n); qr(m);for(int i=1,x;i<=n;i++)qr(a[i]);for(int i=m+1;i<=n;i++)if(a[i]>a[i-m]) puts("Yes");else puts("No");return 0;
}

D D

贪心,低价买高价卖.

int main() {scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);ll money=1000;int i=1;while(i<=n) {int j=i;while(j<=n&&a[j+1]>=a[j])j++;if(j>i)money=money/a[i]*a[j]+money%a[i];i=j+1;}pr2(money); return 0;
}

E E

简单状压.
定义 f [ i ] [ j ] f[i][j] 表示状态 i i , j j 条马路的最小代价.
首先,所有点求到 x , y x,y 轴的最小距离和.
然后我们每次考虑选择一些点计算贡献:
求贡献相当于求一下 x , y x,y 的中位数(相当于一个点上有很多个点)
然后求所有点到中位数的距离和即可.
我们预处理 w [ i ] w[i] 表示状态 i i 的最小开销.

则可以得到 D P DP 方程:
f [ i ] [ j ] = min ? { f [ k ] [ j ? 1 ] + w [ i xor ? k ] } ( k & j = k ) f[i][j]=\min \{f[k][j-1]+w[i \operatorname{xor} k]\}(k\& j=k) .

代码常数有点大…

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=17,size=1<<20,mod=998244353,inf=2e9;//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {char c=gc; x=0; int f=1;while(!isdigit(c)){if(c=='-')f=-1; c=gc;}while(isdigit(c)) x=x*10+c-'0',c=gc;x*=f;
}
template<class o> void qw(o x) {if(x/10) qw(x/10);putchar(x%10+'0');
}
template<class o> void pr1(o x) {if(x<0)x=-x,putchar('-');qw(x); putchar(' ');
}
template<class o> void pr2(o x) {if(x<0)x=-x,putchar('-');qw(x); puts("");
}//math
ll mult(ll a,ll b,ll p) {a=(a%p+p)%p; b=(b%p+p)%p;ll c=(ld)a*b/p;return a*b-c*p;
}
ll gcd(ll a,ll b) {return !a?b:gcd(b%a,a);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll power(ll a,ll b=mod-2) {ll c=1;while(b) {if(b&1) c=c*a%mod;b /= 2; a=a*a%mod;}return c;
}
ll Power(ll a,ll b=mod-2) {ll c=1;while(b) {if(b&1) c=mult(c,a,mod);b /= 2; a=mult(a,a,mod);}return c;
}ll n,x[N],y[N],p[N],w[1<<N],f[1<<N][N],lg[1<<N];struct rec {ll x,y;bool operator <(rec b) const {return x<b.x;}
} a[N];ll calc(int now) {ll tot,s,ans=1e18,tmp,mid;tot=s=0;for(int i=0;i<n;i++)if(now>>i&1) a[++tot]=(rec){x[i],p[i]},s+=p[i];sort(a+1,a+tot+1);mid=s+1>>1;for(int i=1;i<=tot;i++)if(mid<=a[i].y) {tmp=0;for(int j=1;j<=tot;j++) tmp+=a[j].y*abs(a[i].x-a[j].x);ans=min(ans,tmp); break;}else mid-=a[i].y;tot=s=0;for(int i=0;i<n;i++)if(now>>i&1) a[++tot]=(rec){y[i],p[i]},s+=p[i];sort(a+1,a+tot+1);mid=s+1>>1;for(int i=1;i<=tot;i++)if(mid<=a[i].y) {tmp=0;for(int j=1;j<=tot;j++) tmp+=a[j].y*abs(a[i].x-a[j].x);ans=min(ans,tmp); break;}else mid-=a[i].y;return ans;
}int main() {qr(n);for(int i=0;i<=n;i++) lg[1<<i]=i;for(int i=0;i<n;i++)qr(x[i]),qr(y[i]),qr(p[i]);int s=(1<<n)-1;memset(f,63,sizeof f);f[0][0]=0;for(int i=1;i<=s;i++) {f[i][0]=f[i&(i-1)][0];int j=lg[i&-i];f[i][0] += min(abs(x[j]),abs(y[j]))*p[j];}pr2(f[s][0]);for(int i=1;i<(1<<n);i++) w[i]=calc(i);for(int t=1;t<=n;t++) {for(int i=1;i<=s;i++)for(int j=i;	;j=(j-1)&i) {f[i][t]=min(f[i][t],f[j][t-1]+w[i^j]);if(!j) break;}pr2(f[s][t]);}return 0;
}

F F

n ( n 2 ? 1 0 5 ) n(n\le 2*10^5) 架飞机,现在已知他们的坐标和前进方向(上下左右),求最小撞机时间.

设0~3分别表示上下右左.以下简称向上的为0类点,以此类推.

撞击有两种:

  1. \rightarrow \leftarrow .
  2.    ~~\leftarrow
    \uparrow

第一种很容易处理,就是每个点按 x , y x,y 排序,判断 x   o r   y x ~or ~y 相同的情况.

观察第二种情况:两点间的斜率为 ± 1 \pm 1 .
处理的时候我们是按 x x 坐标非降,即从左往右处理.
我们可以定义 f [ i ] [ 0 / 1 ] , g [ i ] [ 0 / 1 ] f[i][0/1],g[i][0/1] .
f f 表示 2 2 类点的贡献, g g 表示 0 / 1 0/1 类点的贡献.
0 / 1 0/1 分别表示斜率为 + 1 , ? 1 +1,-1 .
i i 表示的是直线的截距.

举个例子:
      ~~~~~\leftarrow
  ~\uparrow \uparrow .
  ~\uparrow

假如有两架飞机和向左的飞机相撞,那么为了求最小时间,
我们应该记录每个 截距and斜率 对应状态的最大 x x 坐标.

对于各类点的处理细节:

  1. 和2类点可能相撞, 10 ( y ? f [ y ? x ] [ 1 ] ) 10(y-f[y-x][1]) 为撞击时间,同时有可能和后边的3类点相撞,所以更新 g [ y ? x ] [ 0 ] g[y-x][0]
  2. 类似0号点:和2类点可能相撞, 10 ( y ? f [ y + x ] [ 0 ] ) 10(y-f[y+x][0]) 为撞击时间,更新 g [ y + x ] [ 1 ] g[y+x][1] .
  3. 更新 f [ x + y ] [ 1 ] , f [ y ? x ] [ 0 ] f[x+y][1],f[y-x][0] .
  4. 可能和0/1类点相撞, 10 ( y ? g [ y ? x ] [ 0 ] ) , 10 ( y ? g [ y + x ] [ 0 ] ) 10(y-g[y-x][0]),10(y-g[y+x][0]) 为撞击时间.

细节: y ? x y-x 有可能下溢,所以给它加上 2 ? 1 0 5 2*10^5 .

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=4e5+10,size=1<<20,mod=998244353;
const ll inf=1e18;template<class o> void qr(o &x) {char c=gc; x=0; int f=1;while(!isdigit(c)){if(c=='-')f=-1; c=gc;}while(isdigit(c)) x=x*10+c-'0',c=gc;x*=f;
}
template<class o> void qw(o x) {if(x/10) qw(x/10);putchar(x%10+'0');
}
template<class o> void pr1(o x) {if(x<0)x=-x,putchar('-');qw(x); putchar(' ');
}
template<class o> void pr2(o x) {if(x<0)x=-x,putchar('-');qw(x); puts("");
}int n,dic[150],f[N*2][2],g[N*2][2];
ll ans=inf;
vector<pi> x[N],y[N];int main() {qr(n);dic['U']=0;dic['D']=1;dic['R']=2;dic['L']=3;for(int i=1;i<=n;i++) {int a,b,c;qr(a); qr(b);char str[6]; scanf("%s",str);a++; b++; c=dic[str[0]];x[a].pb(mk(b,c));y[b].pb(mk(a,c));}for(int i=1;i<N;i++) {sort(all(x[i]));sort(all(y[i]));ll a,b;a=b=inf;for(auto j:x[i]) {if(j.se==0) a=j.fi;else if(j.se==1) b=j.fi;if(a<b) ans=min(ans,(b-a)*5);}a=b=inf;for(auto j:y[i]) {if(j.se==2) a=j.fi;else if(j.se==3) b=j.fi;if(a<b) ans=min(ans,(b-a)*5);}}for(int i=1;i<N;i++) for(auto j:x[i]) {int t=j.fi;if(j.se==2) {f[j.fi-i+N][0]=i;f[j.fi+i][1]=i;}else if(j.se==3) {int k=g[j.fi+i][1];if(k) ans=min(ans,(i-k)*10LL);k=g[j.fi-i+N][0];if(k) ans=min(ans,(i-k)*10LL);}else if(j.se==1) {int k=f[j.fi-i+N][0];if(k) ans=min(ans,(i-k)*10LL);g[j.fi+i][1]=i;}else if(j.se==0) {int k=f[j.fi+i][1];if(k) ans=min(ans,(i-k)*10LL);g[j.fi-i+N][0]=i;}}if(ans>inf/2) puts("SAFE");else pr2(ans);return 0;
}
  相关解决方案