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. HDU 3572(Task Schedule) ISAP做法

    题目链接:传送门 题目大意:有n个任务,m个机器.每个机器最早在 Si 天开始,最晚在 Ei 天结束,需要 Pi 天完成.可以中途换机器做,也可以中途打断不做,过后再做   只要在规定时间内都行.每个 ...

  2. activeMQ安装与测试

    Apache ActiveMQ简介 activeMQ是JMS的一种具体的实现,是最流行的,能力强劲的开源消息总线.activeMQ具有以下优势: 多种语言和协议编写客户端(java.C.C++.AJA ...

  3. c# WinForm软件启动拦截(通过更改文件关联实现)

    前几天想做一个软件启动之前拦截的程序,找了下网上的资料没有找到合适的,突然看到电脑软件某看图软件,找到个思路就是跟他一样的,通过修改文件关联进行启动拦截. 原理是这样的,更改.exe默认的启动方式为我 ...

  4. You must reset your password using ALTER USER

    mac mysql error You must reset your password using ALTER USER statement before executing this statem ...

  5. MySQL小记

    一.MyISAM和InnoDB MyISAM引擎是不支持事务的,所以一般开发Mysql的引擎使用InnoDB. 事务处理上方面: MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但 ...

  6. redis 字符串和集合操作

    字符串 redis中的String在在内存中按照一个name对应一个value来存储 set() #在Redis中设置值,默认不存在则创建,存在则修改 r.set('name', 'zhangsan' ...

  7. Webbench进行网站压力测试

    今天突然发现一个新大陆,Webbench,是linux下,用这很方便,开源,不限制并发访问次数和时间....大爱啊! 下载Webbench 使用wget  或者windows下载好导入linux也行, ...

  8. C#笔试面试宝典值得收藏

    又是一年换工作纠结的季节,前一阵子由于工作的缘故,薪资降低,加之被其他部门以莫须有的罪名投诉:固然愤慨之,遂升起离职念想,下面是这几天电话面试和笔试中常问到的问题汇总,给大家分享下,不足之处往大神拍砖 ...

  9. flask实现获取表单并执行shell

    1.一个HTML form input和一个button提供给用户输入 2.使用flask的request获取用户输入的文件名 3.判断输入异常 4.执行shell命令touch aa.txt 并返回 ...

  10. 简述ODS,和数据仓库做简单的比较

    这两天看书,发现了和数据仓库相关的还有一个叫ODS的概念,它是企业级的全局数据库,用于提供集成的,企业级一致的数据,包含如何从各个子系统中向ODS抽取数据以及面向主题的角度存储数据. 它和数据仓库的主 ...