http://codeforces.com/problemset/problem/626/D
预处理出差值,然后组合数学~
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e3+10;
int a[maxn],n;
double summ[5500], f[5500];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int sum=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
sum++;f[abs(a[i]-a[j])]++;
}
}
for(int i=5000;i>=1;i--){
f[i]/=sum;summ[i]=summ[i+1]+f[i];
}
double ans=0;
for(int i=1;i<=5000;i++){
for(int j=1;i+j+1<=5000;j++){
ans+=f[i]*f[j]*summ[i+j+1];
}
}
printf("%.10f\n",ans);
}
肯定是奇数个,反证法即可,若为偶数个,则去掉中间的一个肯定比原来优,因为中位数是除以2,而平均数是除以整个~
固定中间的数,两边取左右最大的数使得平均数最大,因为是二次函数,所以利用二 进制去找每个i对应的极值~
注意double和初值-1~
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+10;
int a[maxn];int n;double sum[maxn];
double get(int i,int j){
double sum1=sum[i-1]-sum[i-1-j];
double sum2=sum[n]-sum[n-j];
return ( (sum1+sum2+(double)a[i])/(double)(2*j+1)-a[i]);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
}
if(n==1){
printf("1\n%d\n",a[1]);return 0;
}
if(n==2){
printf("2\n%d %d\n",a[1],a[2]);return 0;
}
int ans,ansi,ansj,ansize;ansize=0;ans=0;ansi=0;ansj=0;double maxx=-1;
int i,j;i=1;j=1;
for( i=1;i<=n;i++){
int u=0;
for(j=20;j>=0;j--){
u+=(1<<j);
if(i-u<1||n+1-u<=i||get(i,u)<get(i,u-1)) u-=(1<<j);
}
double ans=get(i,u);
if(ans>maxx){
maxx=ans;ansi=i;ansj=u;
}
}
printf("%d\n",2*ansj+1);
for(int i=ansi-ansj;i<=ansi;i++){
printf("%d ",a[i]);
}
for(int i=n-ansj+1;i<=n;i++){
printf("%d ",a[i]);
}
}
这么狗血的dp,反正我是想不出来~
第一维滚动,表示到达第i位,j表示有几个集合是开口的(只有最小值无最大值),k表示当前的待求值和~
更新的时候从小到大排序,然后对应没封口的需要加上相邻两个的差值,以保存目前的k值之和
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int n,K;
ll dp[2][205][1005];
int a[205];
void update(ll &n,int m){
n=(n+m)%mod;
}
int main(){
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int t =0;
dp[0][0][0]=1;
for(int i=1;i<=n;i++){
memset(dp[t^1],0,sizeof(dp[t^1]));
for(int j=0;j<i;j++){
for(int k=0;k<=K;k++){
if(ll now=dp[t][j][k]){//注意int和ll的一致性
ll sum=j*(a[i]-a[i-1]);
if(k+sum<=K){
update(dp[t^1][j][k+sum],now);//单独放一个组结束
update(dp[t^1][j+1][k+sum],now);//开一个组放进去
update(dp[t^1][j][k+sum],now*j%mod);//随意挑一个组放进去
if(j)update(dp[t^1][j-1][k+sum],now*j%mod);//放一个组并关闭一个组
}
}
}
}
t^=1;
}
ll anss=0;
for(int i=0;i<=K;i++){
update(anss,dp[t][0][i]);
}
printf("%lld\n",anss%mod);
}
http://codeforces.com/problemset/problem/627/B
工厂加工大头针,修复之前每天b个,修复之后每天a个,q次询问,问在pi天开始修复,那么到当前为止最多可以满足多少订单~1开头表示设置订单,2开头表示查询~~
开两个树状数组就ok啦~
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+10;
ll A[maxn],ta[maxn],tb[maxn];
ll n,k,a,b,q;
void insert(ll i,ll num,ll *t){//此处上限应该是maxn 或者等于n
for(;i<=n;i+=(i&(-i))) t[i]+=num;
}
ll cal(ll i,ll *t){//此处下限是大于0
ll ans=0;for(;i>0;i-=(i&(-i))) ans+=t[i];
return ans;
}
int main(){
cin>>n>>k>>a>>b>>q;
for(int i=1;i<=q;i++){ int op;ll dd,aa,pp;
scanf("%d",&op);
if(op==1){
scanf("%lld%lld",&dd,&aa);//注意输入一定要对应,不然读不进去
insert(dd,max(0ll,min(b-A[dd],aa)),tb);
insert(dd,max(0ll,min(a-A[dd],aa)),ta);
A[dd]+=aa;
}
else{
scanf("%lld",&pp);
printf("%lld\n",cal(pp-1,tb)+cal(n,ta)-cal(pp+k-1,ta));
}
}
}
http://codeforces.com/problemset/problem/627/C
从起点驾车到终点,给出每个加油站的位置和油价,求使得从起点到终点最小需要的花费~起点处油是满的~
贪心加数据结构的解法
将油按照价格从小到大排序,维护一个set,找到每个站点的油所能供行驶的区间,由于之前加入集合的是价格更小的且已经充满油的点,先二分找到相邻的两个位置,然后新加入的点被之前覆盖的区间都不应该加,因为这些区间用之前价格低的油去走更划算,然后判断油量驱动形势距离是不是d就ok了~
这种用id排序,而不是struct排序的方法也是蛮有趣的~
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int d, n, m;
int x[maxn], p[maxn], idx[maxn];
bool cmp (int x, int y) {
return p[x] < p[y];
}
int main() {
scanf("%d %d %d", &d, &n, &m);
for (int i = 0; i < m; i++) scanf("%d %d", x+i, p+i);
for (int i = 0; i < m; i++) idx[i] = i;
sort(idx, idx+m, cmp);
set<int> data;
data.insert(0);
data.insert(d);
int dist = n;
long long ans = 0;
for (int i = 0; i < m; i++) {
int xi = x[idx[i]];
int pi = p[idx[i]];
int lo = *(--data.lower_bound(xi));
lo = max(lo+n,xi);
int hi = *(data.lower_bound(xi));
hi = min(xi+n,hi);
int diff = max(hi-lo,0);//计算在这个地方买的油走得距离部分
dist += diff;
ans += ((long long)diff)*pi;
data.insert(xi);
}
if (dist == d) printf("%lld\n", ans);
else printf("-1\n");
return 0;
}