Codeforces 8VC Venture Cup

36 篇文章 0 订阅
18 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值