速度训练4 题解

http://acm.hdu.edu.cn/showproblem.php?pid=3552
http://codeforces.com/problemset/problem/352/C
http://codeforces.com/problemset/problem/448/C
http://codeforces.com/problemset/problem/37/D
http://codeforces.com/problemset/problem/57/C
http://codeforces.com/problemset/problem/28/C
http://codeforces.com/problemset/problem/689/E
由于时间原因,题目翻译略.

A

贪心将给定的二元组按照 a 从大到小排序,显然当某个 a 1 值在集合里为最大的时候最好的办法就是贪心把所有 a 值小于 a 1 的二元组全部插入与 a 1 相同的集合.
所以枚举所有 a 1 ,答案即为 a 1 + m a x b 的最小值.

#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;
typedef int fuko[yuzu|10];
typedef pair<int,int> pii;
pii a[yuzu|10];
int main(){
for (int t=read(),i,zxy=0;t--;){
  int n=read(),llx=2e9,maxb=0;
  for (i=1;i<=n;++i) a[i]=pii(read(),read());
  sort(a+1,a+n+1,greater<pii>());
  a[n+1].first=a[0].second=0;
  for (i=1;i<=n;++i) maxb=max(maxb,a[i-1].second),llx=min(llx,a[i].first+maxb);
  /*maxb是目前的b值的最大值,llx是a+b的最小值.*/
  printf("Case %d: %d\n",++zxy,llx);
  }
}

B

题目相当于先将所有数向下取整,再将 n 个数变为向上取整.
d i f ( x ) 为一个数向上取整的值减向下取整的值.
显然 d i f ( x ) x 为整数时取 0 ,否则取 1 .
我们将 a [ i ] d i f 值排序,算出 a [ i ] f l o o r ( a [ i ] ) 值的和 s u m .
那么我们接下来可以贪心,如果 s u m > 0.5 我们就给它 1 ,否则不变.
因为一个 a [ i ] 从向下取整变为向上取整,会带来 1 的贡献,由于要让绝对值最小,所以当 s u m < 0 时就不要动它了.
最后坐等答案出来即可.

#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;
typedef double db;
const int aoi=4038;
typedef db kotori[aoi];
kotori a,f,c,dif;
db sum;
int main(){
int i,n=read()<<1;
for (i=1;i<=n;++i){
  scanf("%lf",&a[i]);
  f[i]=floor(a[i]);
  c[i]=ceil(a[i]);
  dif[i]=c[i]-f[i];
  sum+=c[i]-a[i];
  }
int l=1,r=n;
sort(dif+1,dif+n+1);
for (i=1;i<=n>>1;++i){
  sum-=dif[sum>0.5?r--:l++];
  }printf("%.3lf",abs(sum));
}

C

高妙的动态规划.
接下来首先欣赏xhkxhk大佬暴力压行代码.

#include<bits/stdc++.h>
int i,j=1,a[5010],f[5010][5010];
main(){
    for(std::cin>>i;j<=i;j++)std::cin>>a[j];
    for(;i;i--)for(j=0;j<i;j++)f[i-1][j]=a[j]<a[i]?std::min(f[i][j]+1,f[i][i]+a[i]-a[j]):f[i][i];
    std::cout<<**f;
}

然后介绍介绍标算.
很明显答案不能大于 n (我一列一列涂肯定能够刚好涂完的吧.)
然后我们考虑横着涂.
我们考虑区间 [ l , r ] ,找出区间 l , r 内最小数的位置 m .
然后我们把 [ l , r ] 的最下方涂 a [ m ] 次,这样要涂的部分转化为 [ l , m 1 ] [ m + 1 , r ] 两个部分.
而两个部分的高度都下降了 a [ m ] ,就能够分治解决问题.
这样就可以写出dp方程了.

#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 aoi=5038; /*葵怎么就这么萌啊~*/
int a[aoi];
int dfs(int l,int r,int h){
if (l>r) return 0;
int m=min_element(a+l,a+r+1)-a;
return min(r-l+1,dfs(l,m-1,a[m])+dfs(m+1,r,a[m])+a[m]-h);
/*[l,r]区间涂色的最小次数是r-l+1次.*/
}
int main(){
int i,n=read();
for (i=1;i<=n;++i) a[i]=read();
write(dfs(1,n,0));
}

D

首先预处理组合数逆元.
我们对 x 求一波前缀和,然后对 y 的情况进行 d p .
dp[i][j]表示当前考虑到第 i 个教室,还有 j 人没有分配的方法总数.
枚举当前有 k 人分配到前 i 个教室( k 不能超过 y ),转移方程为
dp[i][j]=(dp[i][j]+dp[i-1][j-k]*zuhe(x[i]-j+k,k)%mod)%mod.
最后用 d p [ m ] [ x [ m ] ] 乘从没有选择的学生中取 x [ i ] 个学生出来的取法总数即可.
数组开小了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 mod=1e9+7,_=150;
ll dp[_][9999],jic[1098]={1},inv[1098];
int x[_],y[_];

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 zuhe(int n,int m){
return jic[n]*inv[m]%mod*inv[n-m]%mod;
}

int main(){
int i,j,k,m=read();
for (i=1;i<1098;++i) jic[i]=jic[i-1]*i%mod;
inv[1097]=kasumi(jic[1097]);
for (i=1096;~i;--i) inv[i]=inv[i+1]*(i+1)%mod; 
for (i=1;i<=m;++i) x[i]=read()+x[i-1];
for (i=1;i<=m;++i) y[i]=read();
memset(dp,0,sizeof dp);
for (**dp=i=1;i<=m;++i){
  for (j=0;j<=x[i];++j){
    for (k=0;k<=min(j,y[i]);++k){
      dp[i][j]=(dp[i][j]+dp[i-1][j-k]*zuhe(x[i]-j+k,k)%mod)%mod;
      }
    }
  }
ll ans=dp[m][x[m]];
for (i=1;i<=m;++i) ans=ans*zuhe(x[m]-x[i-1],x[i]-x[i-1])%mod;
write(ans);
}

E

我们推一下公式.
假设要求不严格单调递增的序列.不严格单调递减同理,减去所有数都一样的 n 种情况即可.
令构造出的序列为 a ,下标是 1 n .我们在 a 的左边加一个 1 ,右边加一个 n .
构造 b [ i ] = a [ i ] a [ i 1 ] ,则 b 序列有 n + 1 项,并且 b 序列的所有数之和为 n 1 .
这种题看起来很像一个隔板法. b 1 + b 2 + . . . + b n + 1 = n 1 .
由于 b 序列可以为 0 ,我们给两边同时加 n + 1 .
那么就变成了在 2 × n 1 个空里插 n 个板的问题了.

#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=2e5,mod=1e9+7;
typedef ll fuko[yuzu|10];
fuko jic={1},inv;

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 zuhe(int n,int m){
return jic[n]*inv[n-m]%mod*inv[m]%mod;
}

int main(){
int i,n=read();
for (i=1;i<=yuzu;++i) jic[i]=jic[i-1]*i%mod;
for (inv[yuzu]=kasumi(jic[yuzu]),i=yuzu-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
write((zuhe(2*n-1,n)*2%mod-n+mod)%mod);
}

F

d p 来解决.
首先预处理组合数.
d p [ i ] [ j ] [ k ] 表示目前处理到第 i 个房间,还有 j 个人,最长队伍是 k 的概率.
枚举当前房间进了 p 个人,概率是从剩下的人中选择了 p 个人,并且他们都进了这个房间的概率.
dp[i][j-p][max(l,k)]+=dp[i-1][j][k]*c[j][p]*pow(1.0/m,p);
最后用 i = 1 n d p [ m ] [ 0 ] [ i ] × i 求得答案.

#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;
typedef double db;
const int _=55;
db c[_][_],dp[_][_][_];
int a[_];
int main(){
int i,j,k,p;
for (i=0;i<=_;++i){
  for (j=0;j<=i;++j){
    c[i][j]=!j?1:c[i-1][j-1]+c[i-1][j];
    }
  }
int n=read(),m=read();
for (i=1;i<=m;++i) a[i]=read();
db llx=0;
memset(dp,0,sizeof dp);
dp[0][n][0]=1;
for (i=1;i<=m;++i){
  for (j=0;j<=n;++j){
    for (p=0;p<=j;++p){
      for (k=0;k<=n;++k){
        int l=ceil(p*1.0/a[i]);
        dp[i][j-p][l>k?l:k]+=dp[i-1][j][k]*c[j][p]*pow(1.0/m,p);
        }
      }
    }
  } 
for (i=1;i<=n;++i) llx+=dp[m][0][i]*i;
printf("%.18lf",llx);
}

G

把这些区间离散化后差分,算每一个最小区间被包括了几次.
如果被包括的次数 x k ,答案即加上长度乘上 C ( x , 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;
const int yuzu=4e5,mod=1e9+7;
typedef ll fuko[yuzu|10];
fuko sum,jic={1},inv,l,r,li;
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 zuhe(int n,int m){
return jic[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
int cnt=0,i,n=read(),k=read();
for (i=1;i<=yuzu;++i) jic[i]=jic[i-1]*i%mod;
inv[yuzu]=kasumi(jic[yuzu]);
for (i=yuzu-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
for (i=1;i<=n;++i){
  l[i]=read(),r[i]=read();
  li[cnt++]=l[i],li[cnt++]=++r[i];
  }
sort(li,li+cnt);
cnt=unique(li,li+cnt)-li;
#define lb lower_bound
for (i=1;i<=n;++i){
  ++sum[lb(li,li+cnt,l[i])-li];
  --sum[lb(li,li+cnt,r[i])-li];
  }
ll llx=0,nk=sum[0];
for (i=1;i<=cnt;++i){
  if (nk>=k) llx=(llx+zuhe(nk,k)*(li[i]-li[i-1])%mod)%mod; nk+=sum[i]; 
  }write(llx);
}

谢谢大家.

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/82695313
今日推荐