T1
T2
T3
T4
T5
T6
T7
由于时间原因,题目翻译略.
A
贪心将给定的二元组按照
a
a
a从大到小排序,显然当某个
a
1
a1
a1值在集合里为最大的时候最好的办法就是贪心把所有
a
a
a值小于
a
1
a1
a1的二元组全部插入与
a
1
a1
a1相同的集合.
所以枚举所有
a
1
a1
a1,答案即为
a
1
+
m
a
x
b
a1+maxb
a1+maxb的最小值.
#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
n
n个数变为向上取整.
令
d
i
f
(
x
)
dif(x)
dif(x)为一个数向上取整的值减向下取整的值.
显然
d
i
f
(
x
)
dif(x)
dif(x)在
x
x
x为整数时取
0
0
0,否则取
1
1
1.
我们将
a
[
i
]
a[i]
a[i]的
d
i
f
dif
dif值排序,算出
a
[
i
]
−
f
l
o
o
r
(
a
[
i
]
)
a[i]-floor(a[i])
a[i]−floor(a[i])值的和
s
u
m
sum
sum.
那么我们接下来可以贪心,如果
s
u
m
>
0.5
sum>0.5
sum>0.5我们就给它
−
1
-1
−1,否则不变.
因为一个
a
[
i
]
a[i]
a[i]从向下取整变为向上取整,会带来
−
1
-1
−1的贡献,由于要让绝对值最小,所以当
s
u
m
<
0
sum<0
sum<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
n
n(我一列一列涂肯定能够刚好涂完的吧.)
然后我们考虑横着涂.
我们考虑区间
[
l
,
r
]
[l,r]
[l,r],找出区间
l
,
r
l,r
l,r内最小数的位置
m
m
m.
然后我们把
[
l
,
r
]
[l,r]
[l,r]的最下方涂
a
[
m
]
a[m]
a[m]次,这样要涂的部分转化为
[
l
,
m
−
1
]
和
[
m
+
1
,
r
]
[l,m-1]和[m+1,r]
[l,m−1]和[m+1,r]两个部分.
而两个部分的高度都下降了
a
[
m
]
a[m]
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
x
x求一波前缀和,然后对
y
y
y的情况进行
d
p
dp
dp.
令dp[i][j]
表示当前考虑到第
i
i
i个教室,还有
j
j
j人没有分配的方法总数.
枚举当前有
k
k
k人分配到前
i
i
i个教室(
k
k
k不能超过
y
y
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
]
]
dp[m][x[m]]
dp[m][x[m]]乘从没有选择的学生中取
x
[
i
]
x[i]
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
n
n种情况即可.
令构造出的序列为
a
a
a,下标是
1
→
n
1\to n
1→n.我们在
a
a
a的左边加一个
1
1
1,右边加一个
n
n
n.
构造
b
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
b[i]=a[i]-a[i-1]
b[i]=a[i]−a[i−1],则
b
b
b序列有
n
+
1
n+1
n+1项,并且
b
b
b序列的所有数之和为
n
−
1
n-1
n−1.
这种题看起来很像一个隔板法.
b
1
+
b
2
+
.
.
.
+
b
n
+
1
=
n
−
1
b_{1}+b_{2}+...+b_{n+1}=n-1
b1+b2+...+bn+1=n−1.
由于
b
b
b序列可以为
0
0
0,我们给两边同时加
n
+
1
n+1
n+1.
那么就变成了在
2
×
n
−
1
2\times n -1
2×n−1个空里插
n
n
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
dp
dp来解决.
首先预处理组合数.
用
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]表示目前处理到第
i
i
i个房间,还有
j
j
j个人,最长队伍是
k
k
k的概率.
枚举当前房间进了
p
p
p个人,概率是从剩下的人中选择了
p
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
\sum_{i=1}^{n}dp[m][0][i]\times i
∑i=1ndp[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
x\geq k
x≥k,答案即加上长度乘上
C
(
x
,
k
)
C(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);
}
谢谢大家.