Codeforces Round #415 (Div.2) A-D 题解

http://codeforces.com/contest/810
这场题目确实不错,E也是挺难的,我看了看数位dp还是算了.

A

你有n个数字,每个数字在1-k之间.
问你最少添加多少个1-k间的数字,使得这些数字的平均数小数部分四舍五入之后等于k.

明显必须添加 k k ,我们可以暴力添加i k k ,看看添加多少个的时候四舍五入等于k.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
int n=read(),k=read();

int main(){
int i,ans=0;
for (i=1;i<=n;++i) ans+=read();
for (i=0;;i++){
  if (floor(1.*(ans+k*i)/(n+i)+0.5)>=k) break;
  }write(i);
}

B

给你n个pair,每个pair包含两个数k,l,你可以选择f个pair,使得这个pair的k乘以二.
求最后所有pair的min(k,l)之和的最大值.

贪心,把这些pair按照一定规则排序,然后模拟求一下.
很明显,排序的依据是当 k×2 k × 2 之后能让 min(k,l) m i n ( k , l ) 增加的数量.
k×2<l k × 2 < l 的时候 增加 k k ,k<l k×2l k × 2 ≥ l 的时候增加 lk l − k .
按照这个排序即可.
一开始按照错误的方法排序wa了好几发.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
struct node{
ll k,l,d;
void rd(){
  k=read(),l=read();
  d=k*2<l?k:k>l?0:l-k;
  }
bool operator <(const node &b) const{
  return d>b.d;
  }
}a[yuzu|10];
int main(){
int i,n=read(),f=read();
for (i=1;i<=n;++i) a[i].rd();
sort(a+1,a+n+1);
ll ans=0;
for (i=1;i<=f;++i) ans+=min(a[i].k*2,a[i].l);
for (i=f+1;i<=n;++i) ans+=min(a[i].k,a[i].l);
write(ans);
}

C

定义F(a)是集合a中最大的元素减去最小元素的差.给出一个集合,求该集合的所有子集的F函数值之和mod 10^9+7.
从小到大排序,枚举每一个元素作为子集的最小元素.
我们来看一下,当最小元素是 a[1] a [ 1 ] 的时候,看看最大元素,比如说最大元素是 a[i] a [ i ] ,则必然有 2i2 2 i − 2 个集合符合这样的条件.( a[2i] a [ 2 − i ] 都可以任意取或者不取.)
此时需要减掉 a[1] a [ 1 ] 的个数就是 20+21+22+...+2n2 2 0 + 2 1 + 2 2 + . . . + 2 n − 2 .
减掉 a[2] a [ 2 ] 的个数是 20+21+22+23+...2n3 2 0 + 2 1 + 2 2 + 2 3 + . . .2 n − 3 .
我们可以算出减去每一个数的个数.
接下来将每个最大元素对应的集合个数覆盖上去,列表如下:

最小元素   最大元素   a[1] a[2] a[3] a[4] a[5] ... a[n]
a[1]                0    1    2     4   8       2^(n-2)
a[2]                      0     1    2   4       2^(n-3)
a[3]                            0   1   2       2^(n-4) 

发现了吧.
加上 a[n] a [ n ] 的个数很明显和减去 a[1] a [ 1 ] 的个数相等.
因此这样对每个数求两个等比数列之和即可.
如果预处理 2 2 的幂次,时间复杂度还能够更低.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=3e5,mod=1e9+7;
typedef ll fuko[yuzu|10];
fuko a;

ll kasumi(ll a,ll b=mod-2){
ll s=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) s=s*a%mod;
return s;
}

ll he(int q,int l,int r){
if (l>r) return 0;
return (kasumi(q,r+1)-kasumi(q,l)+mod)%mod;
}

int main(){
int i,n=read();
for (i=1;i<=n;++i) a[i]=read();
sort(a+1,a+n+1);
ll llx=0;
for (i=1;i<=n;++i){
  llx=(llx+a[i]*he(2,0,i-2)-a[i]*he(2,0,n-i-1)+mod)%mod;
  }write(llx);
}

D

交互题.
从1-n n个数里,电脑选择其中k个数组成的一个集合.你需要猜出这k个数中的两个.
你每次可以询问x,y两个数,定义a是k个数中最接近x的数,b是k个数中最接近y的数.
如果|x-a|<=|y-b|,回复是"TAK",否则是"NIE".你最多询问60次.
询问的格式是"1 x y",给出的答案是"2 x y",给出答案后立即结束程序.

我们每次询问连续的两个数,如果答案是TAK,左边肯定有一个数,否则右边肯定有一个数.
这样二分可以找出一个数.
然后在x的左边或者右边找到另一个数 y y <script type="math/tex" id="MathJax-Element-1456">y</script>即可.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
int n,k,a,b;

bool query(int x,int y){
if (x<0||y>n) return 0;
printf("1 %d %d\n",x,y);
fflush(stdout);
string ans;cin>>ans;
return ans=="TAK";
}

int get(int l,int r){
if (l>r) return -1;
for (;l<r;){
  int mid=l+r>>1;
  query(mid,mid+1)?r=mid:l=mid+1;
  } 
return l;
}

int main(){
n=read(),k=read();
a=get(1,n),b=get(1,a-1);
if (!query(b,a)) b=get(a+1,n);
printf("2 %d %d\n",a,b);
}

谢谢大家.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值