AtCoder Regular Contest 096


C - Many Medians

题意:

有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c。

求买X个A和Y个B最小花费使多少。

分析:

明显的发现肯定买性价比更高的方案,分情况讨论一下,如果\(a+b<=2*c\),那么明显的先买足c到A,B中较小的一个,然后再比较一下剩下的那个的单价和\(2*c\)的大小。

A[ans=] -->|a+b<=2*c| B(A*a+B*b)
A --> |else| C{2*c}
C --> |A<=B| D[*A]
C --> |else| E[*B]
D --> |b<=2*c| F[+b*B-b*A]
D --> |else| G[+2*c*B-2*c*A]
E --> |a<=2*c| H[+a*A-a*B]
E --> |else| I[+2*c*A-2*c*B]
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define MAXN 4000007
#define mo 19930726
#define ll long long
using namespace std;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
ll a,b,c,x,y,ans;
int main()
{
cin>>a>>b>>c>>x>>y;
ll minn=min(x,y);
if(a+b<=2*c){
cout<<x*a+y*b;
} else {
ans+=minn*c*2;
if(x<y){
if(2*c<=b) b=2*c;
ans+=b*(y-x);
} else {
if(2*c<=a) a=2*c;
ans+=a*(x-y);
}
cout<<ans;
}
}

D - Static Sushi

题意:

有n个寿司围成一圈,给出寿司离起点的距离v和寿司的价值x,从起点开始走,任意时刻都可以决定走的方向,并且可以在任意时刻停下,求\(max(\sum x-\sum v)\)。

分析:

可以考虑我们一共有几种选择,可以发现最优的情况一定是向一个方向走然后掉头走另一个方向。前缀和求一下,顺时针逆时针直接搞搞也就出来了。

#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define MAXN 200007
#define mo 19930726
using namespace std;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
#define ll long long
const int inf = 0x3f3f3f3f;
ll n,v[MAXN],x[MAXN],C,sum[MAXN],pre[MAXN],ans;
int main()
{
cin>>n>>C;
for(int i=1;i<=n;i++){
cin>>x[i]>>v[i];
sum[i]=sum[i-1]+v[i];
pre[i]=max(pre[i-1],sum[i]-x[i]);
}
ll cnt=0;
ll c=C;
for(int i=n;i>=1;i--){
ans=max(ans,cnt+pre[i]);
cnt+=v[i]-2*(c-x[i]);
c=x[i];
}
for(int i=1;i<=n;i++) x[i]=C-x[i];
reverse(x+1,x+n+1);
reverse(v+1,v+n+1);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+v[i];
pre[i]=max(pre[i-1],sum[i]-x[i]);
}
cnt=0;
c=C;
for(int i=n;i>=1;i--){
ans=max(ans,cnt+pre[i]);
cnt+=v[i]-2*(c-x[i]);
c=x[i];
}
cout<<ans;
}

E - Everything on It

题意:

给你n种酱,可以任意添加入拉面中。你可以有任意碗拉面,然后你可以选择加入和不加这n种酱的任意一种进去任意一碗拉面中,问你怎么添加,使得:

1.这任意碗拉面中,不存在两碗拉面加的酱相同。

2.这任意碗拉面中,每一种酱都至少加入过两碗拉面中。

满足以上两个条件的加酱方法算一种方案。问有多少种方案%mod。

分析:

不难看出这题应该是一个容斥。

我们不犯设\(f[i]\)为有i种酱不合条件时的方案数,那么明显可以求出答案是\(\sum_{i=0}^n (-1)^if[i]C_n^i\)。

那么明显我们只需要求出\(f\)就可以轻松得到ans。

建立另一个数组\(g[i][j]\)表示前j碗拉面中有i种酱不符合条件的方案数。我们可以用类第二类斯特林数的方式求出来,\(g[i][j]=g[i-1][j-1]+g[i-1][j]*(j+1)\)。

可以这么想,当我们递推过来时,如果前\(i-1\)种酱在\(j-1\)碗面中,那么第\(i\)种酱一定在第\(j\)碗面中。如果前\(i-1\)种酱在前\(j\)碗面中,那么第\(i\)种酱就可在任何一碗面中或者压根就不在任何一碗面中。

之后求出\(f[i]=\sum_{j=0}^ig[i][j]2^{(n-i)j} 2^{2^{(n-i)}}\)

然后用这个公式

\(a^n \equiv a^{n\cdot mod(p-1)}(modp)\)

再直接往\(\sum_{i=0}^n (-1)^if[i]C_n^i\)这东西里面套就行了。

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define MAXN 3007
#define ll long long
using namespace std;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
ll c[MAXN][MAXN];
ll g[MAXN][MAXN];
ll n,mo;
inline ll niubide_power(ll k,ll x,ll mod)
{
ll ans=1;
while(x) {
if(x&1ll) ans=ans*k%mod;
k=(k*k%mod);
x>>=1;
}
return ans;
}
int main()
{
cin>>n>>mo;
for(re int i=1;i<=n;i++){
c[i][0]=1;c[i][i]=1;
for(int j=1;j<i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo;
}
for(int i=0;i<=n;i++){
g[i][0]=1;
for(int j=1;j<=i;j++)
g[i][j]=(g[i-1][j-1]+g[i-1][j]*(j+1)%mo)%mo;
}
ll ans=0;
for(int i=0;i<=n;i++){
ll k=c[n][i];
if(i&1) k=(mo-k)%mo;
ll kind=niubide_power(2,n-i,mo);
ll x=niubide_power(2,n-i,mo-1);
x=niubide_power(2,x,mo);
ll cnt=0,y=1;
for(int j=0;j<=i;j++){
cnt=(cnt+(g[i][j]*y)%mo)%mo;
y=kind*y%mo;
}
ans=(ans+(k*cnt)%mo*x%mo)%mo;
}
cout<<ans;
}

F - Sweet Alchemy

题意:

\(n≤50\) 的树,每个点有权值,现要选点(可多次选一个点)使点数尽量多,如下限制:

选的总权值不超过\(C≤1e9\);\(c_i\) 表示\(i\)选的次数,\(p_i\) 表示 \(i\) 的父亲,那么\(c_{p[i]}≤c_i≤c_{p[i]}+D\)

\(D≤1e9\)是给定常数。

分析:

首先我们可以差分一下这棵树,然后这个题就变成了:在一棵树上有不超过50 个节点,每个节点均有一个权值及一个代价,除1号节点外每个节点选择的次数均不能超过 D。求在总代价不超过x的前提下,如何使权值最大化?

看上去像是一个经典的背包问题,但是超大的背包容量你也背不起来。

突破口貌似是\(n\le50\)这极少的物品个数。

但是突破不了了。

看了题解觉得真是非常神仙。

首先背包问题有一个经典错解,就是那个性价比高选哪个,但是明显错误的就是这样可能会造成包内有大量剩余空间没得使用浪费掉,但实际上是有更优秀的解的。

考虑什么时候我们能用性价比更高的物品替换到性价比低的。假设我们有\(v_i\),\(w_i\)和\(v_j\),\(w_j\),且\(\frac{v_i}{w_i}>\frac{v_j}{w_j}\)。那么我们在选了\(v_i\)个\(j\)物品,就相当于选了\(v_j\)个\(i\)物品。因为权值没有变化,但是代价却更小了。

所以我们不能直接替换的最多只有\(v_i-1\)这么多,而\(v\)的足够小的范围是可以接受的。所以直接把每件物品都取\(min(D,n)\)件然后多重背包就可以了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define re register
#define MAXN 507
#define mo 19930726
#define ll long long
#define int ll
using namespace std;
typedef unsigned long long ull;
#define ms(arr) memset(arr, 0, sizeof(arr))
const int inf = 0x3f3f3f3f;
int n,X,D,ans,num,dp[125500];
int w[MAXN],val[MAXN],pos[MAXN],head[MAXN];
int tot,V[MAXN*MAXN],W[MAXN*MAXN],cnt;
struct po
{
int nxt,to;
}edge[MAXN<<1];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int from,int to)
{
edge[++num].nxt=head[from];
edge[num].to=to;
head[from]=num;
}
void dfs(int u)
{
val[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
dfs(v);
w[u]+=w[v];val[u]+=val[v];
}
cnt+=val[u]*n; pos[u]=u;
}
inline bool cmp(int x,int y){return val[x]*w[y]>val[y]*w[x];}
main()
{
n=read();X=read();D=read();
w[1]=read();
for(re int i=2;i<=n;i++){
w[i]=read();int x=read();
add_edge(x,i);
}
dfs(1);
sort(pos+1,pos+n+1,cmp);
int tmp=min(n,D);
for(re int i=1;i<=cnt;i++) dp[i]=inf;
for(re int i=1;i<=n;i++){
int len=1,lim=tmp;
while(lim>=len){
V[++tot]=len*val[pos[i]];
W[tot]=len*w[pos[i]];
lim-=len,len<<=1;
}
if(lim) V[++tot]=lim*val[pos[i]],W[tot]=lim*w[pos[i]];
}
for(int i=1;i<=tot;i++)
for(int j=cnt;~j;j--){
if(j>=V[i]) dp[j]=min(dp[j],dp[j-V[i]]+W[i]);
}
int ans=0;
for(int i=0;i<=cnt;i++){
if(dp[i]>X) continue;
int ret=i,left=X-dp[i];
for(int j=1;j<=n;j++){
int tem=pos[j],used=min(max(D-n,0ll),left/w[tem]);
if(tem==1) used=left/w[tem];
left-=w[tem]*used;
ret+=val[tem]*used;
}
ans=max(ans,ret);
}
cout<<ans;
}

AtCoder Regular Contest 096的更多相关文章

  1. [AtCoder Regular Contest 096 E] Everything on It 解题报告 (第二类斯特林数+容斥原理)

    题目链接:https://arc096.contest.atcoder.jp/tasks/arc096_c Time limit : 4sec / Memory limit : 512MB Score ...

  2. Atcoder Regular Contest 096 D - Sweet Alchemy(贪心+多重背包)

    洛谷题面传送门 & Atcoder 题面传送门 由于再过 1h 就是 NOI 笔试了所以题解写得会略有点简略. 考虑差分,记 \(b_i=c_i-c_{fa_i}\),那么根据题意有 \(b_ ...

  3. Atcoder Regular Contest 096 C - Everything on It(组合数学)

    Atcoder 题面传送门 & 洛谷题面传送门 简单题,由于这场 arc 的 F 是 jxd 作业而我不会做,所以只好来把这场的 E 水掉了. 我们记 \(f(i)\) 为钦定 \(i\) 个 ...

  4. AtCoder Regular Contest 096 D - Static Sushi(线性dp)

    Problem Statement "Teishi-zushi", a Japanese restaurant, is a plain restaurant with only o ...

  5. AtCoder Regular Contest 061

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

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

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

  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. leveldb学习笔记

    LevelDB由 Jeff Dean和Sanjay Ghemawat开发. LevelDb是能够处理十亿级别规模Key-Value型数据持久性存储的C++ 程序库. 特别如下: 1.LevelDb是一 ...

  2. Android 4.4 (KitKat) SMS Apis Change——Android 4.4的一个重大变化

    Android团队通过Android开发博客透漏今年会放出Android 4.4 (KitKat) ,同时更新了 SMS 的部分API.博客上讲只有default SMS app才能对短信数据库有写权 ...

  3. CodeForces 667A Pouring Rain

    A. Pouring Rain time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  4. 读 下一代SOA 服务技术与面向服务简明指南

    面向服务的八个设计原则 标准化服务合同 在同一个服务仓库中的服务都符合同样的合同设计标准 服务松耦合 服务合同施加了消费者低耦合的要求,而它们自己也与周围的环境脱钩 服务抽象 服务合同只包含基本信息, ...

  5. 学习使用turtlebot2——安装ROS Indigo系统

    最近在学习使用turtlebot2,特此做一些学习记录. 安装ROS前要先决定自己电脑的Ubuntu(乌班图)系统.现在学习ROS常使用的Ubuntu系统有Ubuntu 16.04 和Ubuntu14 ...

  6. 数据库操作(使用FMDB)

    iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便.于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.PlausibleDatabase.sqlitepers ...

  7. 页面的日志服务 web页面渲染 服务 ; 服务耦合带来的问题

    情景: 虽然对web服务做了3节点的负载均衡,但是由于埋点数据的落盘的代码也在相同服务器上,导致当flume处理日志的吞吐量达到瓶颈时,3节点的请求积压,挤占服务器资源,导致接口数据处理迟缓,页面加载 ...

  8. java基础10 吃货联盟点餐系统

    public class OrderMsg { public static void main(String[] args) throws Exception { /** * 订餐人姓名.选择菜品.送 ...

  9. 请写出用于校验HTML文本框中输入的内容全部为数字的javascript代码

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html ...

  10. 阿里云配置mysql远程连接

    默认是不能用客户端远程连接的,阿里云提供的help.docx里面做了设置说明,mysql密码默认存放在/alidata/account.log 首先登录: mysql -u root -h local ...