牛客网多校第五场

A:gpa

 分数规划裸题了吧,然后二分次数过多的话会超时

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int MAX=1e5+5;
int n,k;
double s[MAX],c[MAX];
double tmp[MAX];
 
int check(double x){
    int i;
    double ans=0;
    for(i=0;i<n;i++)
        tmp[i]=s[i]*c[i]-x*s[i];
    sort(tmp,tmp+n);
    for(i=n-1;i>=k;i--)
        ans+=tmp[i];
    if(ans>0) return 1;
    return 0;
}
 
double bsearch(double left,double right){
    int i;
    double mid;
     
    for(i=0;i<60;i++){
        mid=(left+right)/2;
        if(check(mid))
            left=mid;
        else
            right=mid;
    }
    return mid;
}
 
int main(){
    int i;
     
    scanf("%d%d",&n,&k);
    for(i=0;i<n;i++)
        scanf("%lf",&s[i]);
    for(i=0;i<n;i++)
        scanf("%lf",&c[i]);
    double ans=bsearch(0,1e9);
    printf("%.7lf\n",ans);
     
    return 0;
}
View Code

B: div

 主要是结论比较难构造出来,当然如果oeis技巧足够强,这就是小事。推出结论就很简单了,java大数随便写写就好了

附结论证明

import java.math.BigInteger;
import java.util.Scanner;
 
public class Main {
    public static void main(String[] args)
    {
        Scanner cin = new Scanner(System.in);
        BigInteger m=cin.nextBigInteger();
        BigInteger a1 =new BigInteger("0");
        BigInteger a2 =new BigInteger("2");
        BigInteger b1 =new BigInteger("0");
        BigInteger b2 =new BigInteger("6");
        BigInteger a3,b3;
        BigInteger k1 =new BigInteger("6");
        BigInteger k2 =new BigInteger("14");
        while(a2.compareTo(m)<=0)
        {
            a3=a2.multiply(k1).subtract(a1);
            a1=a2;
            a2=a3;     
        }
         
        while(b2.compareTo(m)<=0)
        {
            b3=b2.multiply(k2).subtract(b1);
            b1=b2;
            b2=b3;     
        }
         
        System.out.println(a2.min(b2));
    }
}
View Code

 

D: inv

 b数组的逆序数对拿树状数组搞一搞。性质:得到最优解的插入顺序一定会按照升序插入,所以不用care插入的先后顺序,直接按当前的最优解来就可以,线段树维护答案

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#include <iostream>
#include <stack>
#include <set>
#include <map>
#define ll __int128
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
using namespace std;

const int MAX=2e5+5;
int n,a[MAX],b[MAX],c[MAX],pos[MAX];
long long ans;

int lowbit(int x){
    return x&(-x);
}

void add(int pos,long long val){  //单点加值 
    while(pos<MAX){
        a[pos]=a[pos]+val;
        pos+=lowbit(pos);
    }
}

long long getsum(int pos){   //1--pos求和 
    long long sum=0;
    while(pos>0){
        sum=sum+a[pos];
        pos-=lowbit(pos);
    }
    return sum;
}

int lazy[MAX*4],xds[MAX*4];

void pushup(int x){
    xds[x]=min(xds[x<<1],xds[x<<1|1]);
}

void pushdown(int x){
    if(lazy[x]){
        xds[x<<1]+=lazy[x];
        xds[x<<1|1]+=lazy[x];
        lazy[x<<1]+=lazy[x];
        lazy[x<<1|1]+=lazy[x];
        lazy[x]=0;
    }
}

void js(int l,int r,int x){
    int m=(l+r)/2;
    
    if(l==r){
        xds[x]=c[l];
        return;
    }
    js(LSON);
    js(RSON);
    lazy[x]=0;
    pushup(x);
}

void xg(int L,int R,int val,int l,int r,int x){
    int m=(l+r)/2;

    if(l==L&&r==R){
        xds[x]+=val;
        lazy[x]+=val;
        return;
    }
    pushdown(x);
    if(R<=m) 
        xg(L,R,val,LSON);
    else if(L>m) 
        xg(L,R,val,RSON);
    else{
        xg(L,m,val,LSON);
        xg(m+1,R,val,RSON);
    }
    pushup(x);
}

int main(){
    int i;
    
    scanf("%d",&n);
    int m=n/2;
    for(i=1;i<=m;i++){
        scanf("%d",&b[i]);
        pos[b[i]]=i;
        add(b[i],1);
        ans+=i-getsum(b[i]);
    }
    m++; 
    for(i=1;i<=m;i++) c[i]=i-1;
    js(1,m,1);
    for(i=3;i<n;i+=2){
        xg(1,pos[i-1],1,1,m,1);
        xg(pos[i-1]+1,m,-1,1,m,1);
        ans+=xds[1];
    }
    printf("%lld\n",ans);
    
    return 0;
}
View Code

 

E:room

 二分图最大权值匹配,将旧安排和新安排两两之间建边,容量为1,权值为这两个房间相同人的数量。因为凡是前后不在同一个宿舍的人可以只通过一次就交换到新宿舍,所以只要不交换的人尽量多即可

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#include <set>
using namespace std;
 
const int INF=0x3f3f3f3f;
const int MAX=1e3+5;
const int ext=200;
struct node{
    int v,f,cost,next;
}edge[MAX*MAX];
int no,s,t;
int head[MAX],dis[MAX],vis[MAX],pre[MAX],rec[MAX]; //pre记录前驱 rec记录边在edge中编号
queue<int> q;
 
void init(void){
    no=0;
    memset(head,-1,sizeof head);
}
 
void addedge(int u,int v,int f,int cost){
    edge[no].v=v; edge[no].f=f; edge[no].cost=cost;
    edge[no].next=head[u]; head[u]=no++;
    edge[no].v=u; edge[no].f=0; edge[no].cost=-cost;
    edge[no].next=head[v]; head[v]=no++;
}
 
int spfa(int s,int t){
    int k,tp;
     
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    while(!q.empty())
        q.pop();
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    while(!q.empty()){
        tp=q.front();
        q.pop();
        vis[tp]=0;
        for(k=head[tp];k!=-1;k=edge[k].next)
            if(dis[edge[k].v]>dis[tp]+edge[k].cost&&edge[k].f){
                dis[edge[k].v]=dis[tp]+edge[k].cost;
                pre[edge[k].v]=tp;
                rec[edge[k].v]=k;
                if(vis[edge[k].v]==0){
                    vis[edge[k].v]=1;
                    q.push(edge[k].v);
                }
            }
    }
    if(dis[t]==INF)
        return 0;
    return 1;
}
 
pair<int, int> Mcmf(int s,int t){
    int minflow,k,mincost=0,maxflow=0;
    while(spfa(s,t)){
        k=t;
        minflow=INF;
        while(k!=s){
            minflow=min(minflow,edge[rec[k]].f);
            k=pre[k];
        }
        k=t;
        maxflow+=minflow;
        while(k!=s){
            mincost+=minflow*edge[rec[k]].cost;
            edge[rec[k]].f-=minflow;
            edge[rec[k]^1].f+=minflow;
            k=pre[k];
        }
    }
    return make_pair(maxflow,mincost);
}
 
int n;
int x[MAX][10],y[MAX][10];
 
int main(){
    int i,j,k,p;
     
    init();
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        for(j=0;j<4;j++)
            scanf("%d",&x[i][j]);
    for(i=1;i<=n;i++){
        for(j=0;j<4;j++)
            scanf("%d",&y[i][j]);
        for(j=1;j<=n;j++){
            int cnt=0;
            for(k=0;k<4;k++)
                for(p=0;p<4;p++)
                    if(y[i][k]==x[j][p])
                        cnt++;
        addedge(j,i+ext,1,4-cnt);
        }
    }
    int s=0,t=200+ext;
    for(i=1;i<=n;i++){
        addedge(s,i,1,0);
        addedge(i+ext,t,1,0);
    }  
    pair<int,int> ans=Mcmf(s,t);
    printf("%d\n",ans.second);
     
    return 0;
}
View Code

F: take

 首先这道题可以算每个点对答案的贡献,考虑一下我翻出这张并且换的概率是什么,设dp[i]表示i拿到了钻石并且更换了一次的概率:那么dp[i]=p[i]*∑(dp[j]*q[j]) 0<=j<i且D[j]<D[i],这里q[j]表示从j到i从没发生一次更换的可能性,可以发现∑里面的东西可以用线段树维护出来

  1 #include<cctype>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<algorithm>
  6 
  7 #define maxn 100000+5
  8 
  9 using namespace std;
 10 
 11 typedef long long LL;
 12 
 13 const int mod=998244353;
 14 
 15 struct Seg_Tree {
 16     int l, r;
 17     int tag, sum;
 18 }tr[maxn << 2];
 19 
 20 int p[maxn],d[maxn],c[maxn],dp[maxn];
 21 int n,cnt,tot,ans;
 22 
 23 void Update(int k)
 24 {
 25     tr[k].sum = (tr[k << 1].sum + tr[k << 1 | 1].sum)%mod;
 26 }
 27 
 28 void Pushdown(int k)
 29 {    
 30     if (tr[k].tag!=1) {
 31         tr[k << 1].sum = (LL)tr[k<<1].sum*tr[k].tag%mod; 
 32         tr[k << 1 | 1].sum = (LL)tr[k<<1|1].sum*tr[k].tag%mod;
 33         tr[k << 1].tag=(LL)tr[k<<1].tag*tr[k].tag%mod; 
 34         tr[k << 1 | 1].tag=(LL)tr[k<<1|1].tag*tr[k].tag%mod;
 35         tr[k].tag = 1;
 36     }
 37 }
 38 
 39 void Build(int k, int l, int r)
 40 {
 41     tr[k].l = l; tr[k].r = r;
 42     if (l == r) {
 43         tr[k].sum = 0;
 44         tr[k].tag = 1;
 45         return;
 46     }
 47     int mid = (l + r) >> 1;
 48     Build(k << 1, l, mid);
 49     Build(k << 1 | 1, mid + 1, r);
 50     Update(k);
 51 }
 52 
 53 void Insert(int k,int pos,int val)
 54 {
 55     Pushdown(k);
 56     if(tr[k].l==tr[k].r){
 57         tr[k].sum=(tr[k].sum+val)%mod;
 58         return;
 59     }
 60     if(pos<=tr[k<<1].r) Insert(k<<1,pos,val);
 61     else Insert(k<<1|1,pos,val);
 62     Update(k);
 63 }
 64 
 65 void Modify(int k, int l, int r, int val)
 66 {
 67     Pushdown(k);
 68     if (tr[k].l == l && tr[k].r == r) {
 69         tr[k].sum = (LL)tr[k].sum*val%mod; 
 70         tr[k].tag = (LL)tr[k].tag*val%mod;
 71         return;
 72     }
 73     if (tr[k << 1].r >= r) Modify(k << 1, l, r, val);
 74     else if (tr[k << 1 | 1].l <= l) Modify(k << 1 | 1, l, r, val);
 75     else Modify(k << 1, l, tr[k << 1].r, val), Modify(k << 1 | 1, tr[k << 1 | 1].l, r, val);
 76     Update(k);
 77 }
 78 
 79 int Query(int k, int l, int r)
 80 {
 81     Pushdown(k);
 82     if (tr[k].l == l && tr[k].r == r) return tr[k].sum;
 83     if (tr[k << 1].r >= r) return Query(k << 1, l, r);
 84     else if (tr[k << 1 | 1].l <= l) return Query(k << 1 | 1, l, r);
 85     else return (Query(k << 1, l, tr[k << 1].r) + Query(k << 1 | 1, tr[k << 1 | 1].l, r))%mod;
 86 }
 87 
 88 int qpow(int a,int b)
 89 {
 90     int ans=1,base=a;
 91     while(b){
 92         if(b&1) ans=(LL)ans*base%mod;
 93         base=(LL)base*base%mod;
 94         b>>=1;
 95     }
 96     return ans;
 97 }
 98 
 99 int bsearch(int x)
100 {
101     int l=1,r=tot,ans;
102     while(l<=r){
103         int mid=(l+r)>>1;
104         if(c[mid]<=x) ans=mid,l=mid+1;
105         else r=mid-1;        
106     }
107     return ans;
108 }
109 
110 int main()
111 {
112     int n;
113     scanf("%d", &n);
114     c[++cnt]=0;
115     int inv=qpow(100,mod-2);
116     for (int i = 1; i <= n; i++){
117         scanf("%d%d", &p[i],&d[i]);
118         c[++cnt]=d[i];
119         p[i]=(LL)p[i]*inv%mod;
120     }    
121     sort(c+1,c+1+cnt); c[0]=-1;
122     for(int i=1;i<=cnt;i++)
123         if(c[i]!=c[i-1]) c[++tot]=c[i];
124     for(int i=1;i<=n;i++)
125         d[i]=bsearch(d[i]);
126     Build(1, 1, tot);
127     Insert(1,1,1);
128     
129     for(int i=1;i<=n;i++){
130         dp[i]=(LL)p[i]*Query(1,1,d[i]-1)%mod;
131         ans=(ans+dp[i])%mod;
132         Modify(1,1,d[i]-1,((1-p[i])%mod+mod)%mod);
133         Insert(1,d[i],dp[i]);             
134     }
135     printf("%d",ans);
136     
137     return 0;
138 }
View Code

 

G:max

 取[1,n/c]中的最大两个就行,然后特别讨论一下n/c=1情况

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#include <iostream>
#include <stack>
#include <set>
#include <map>
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
using namespace std;
 
long long c,n;
 
int main(){
     
    scanf("%lld%lld",&c,&n);
    long long x=n/c;
    if(x<1){
        puts("-1");
        return 0;
    }
    if(x==1){
        printf("%lld\n",c*c);
        return 0;
    }
    long long ans=x*(x-1);
    printf("%lld\n",ans*c*c);
     
    return 0;
}
View Code

 

H:subseq

 线段树从后向前维护以当前为起点的上升子序列的个数,再从前向后找第k个就好,爆longlong直接赋值INF无解

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack> 
#include <set>
#define LSON l,m,x<<1
#define RSON m+1,r,x<<1|1
using namespace std;

const long long INF=1e18+5;
const int MAX=5e5+5;
int n,a[MAX];
long long big[MAX];
long long k,seg[MAX<<2];
vector<int> V;
vector<int> ans;

void update(int pos,long long val,int l,int r,int x){
    if(l==r){
        seg[x]+=val;
        if(seg[x]>INF) seg[x]=INF; 
        return ;
    }
    int m=l+r>>1;
    if(pos<=m) update(pos,val,LSON);
    else update(pos,val,RSON);
    long long left=seg[x<<1],right=seg[x<<1|1];
    if(left>INF||right>INF) seg[x]=INF;
    else seg[x]=left+right;
    if(seg[x]>INF) seg[x]=INF;
}

long long query(int L,int R,int l,int r,int x){
    if(L>R) return 0;
    if(L<=l&&R>=r) return seg[x];
    int m=l+r>>1;
    long long ans=0;
    if(R<=m) ans=query(L,R,LSON);
    else if(L>m) ans=query(L,R,RSON);
    else{
        long long left=query(L,m,LSON),right=query(m+1,R,RSON);
        if(left>INF||right>INF) ans=INF;
        else ans=left+right;
    }
    if(ans>INF) ans=INF;
    return ans;
}

int main(){
    int i;
    
    scanf("%d%lld",&n,&k);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
        V.push_back(a[i]);
    }
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    for(i=n-1;i>=0;i--){
        int id=lower_bound(V.begin(),V.end(),a[i])-V.begin()+1;
        long long rk=query(id+1,V.size(),1,V.size(),1);
        rk++;
        big[i]=rk;
        update(id,rk,1,V.size(),1);
    }
    int sta=0;
    for(i=0;i<n;i++){
        if(sta>=a[i]) continue;
        if(k==0) break;
        if(big[i]>=k){
            sta=a[i];
            k--;
            ans.push_back(i+1);
        }
        else k-=big[i];
    }
    if(k==0){
        printf("%d\n",ans.size());
        for(i=0;i<ans.size();i++) printf("%d ",ans[i]);
    }
    else puts("-1");
    
    return 0;
} 
View Code

 

I:vcd

 |S|=1时必选 |S|=2时选y坐标不相同的两个 |S|=3时要选摆成<形状的三个点 |S|>3时一定不可选

对于|S|=3的部分,可按x坐标排序后倒序处理,用线段树维护这些点的y坐标即可。

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<algorithm>
  6 
  7 #define maxn 200000+5
  8 
  9 using namespace std;
 10 
 11 typedef long long LL;
 12 
 13 const int mod=998244353;
 14 
 15 struct Point{
 16     int x,y;
 17     bool operator <(const Point &T)const{
 18         if(y==T.y) return x>T.x;
 19         return y>T.y;
 20     }
 21 }p[maxn];
 22 
 23 struct Seg_Tree {
 24     int l, r;
 25     int sum;
 26 }tr[maxn << 4];
 27 
 28 vector <int> s[maxn];
 29 
 30 int c[maxn<<1];
 31 int n,tot,cnt;
 32 
 33 void Update(int k)
 34 {
 35     tr[k].sum = (tr[k << 1].sum + tr[k << 1 | 1].sum)%mod;
 36 }
 37 
 38 void Build(int k, int l, int r)
 39 {
 40     tr[k].l = l; tr[k].r = r;
 41     if (l == r) {
 42         tr[k].sum = 0;
 43         return;
 44     }
 45     int mid = (l + r) >> 1;
 46     Build(k << 1, l, mid);
 47     Build(k << 1 | 1, mid + 1, r);
 48     Update(k);
 49 }
 50 
 51 void Insert(int k,int pos)
 52 {
 53     if(tr[k].l==tr[k].r){
 54         tr[k].sum=(tr[k].sum+1)%mod;
 55         return;
 56     }
 57     if(pos<=tr[k<<1].r) Insert(k<<1,pos);
 58     else Insert(k<<1|1,pos);
 59     Update(k);
 60 }
 61 
 62 int Query(int k, int l, int r)
 63 {
 64     if(l>r) return 0;
 65     if (tr[k].l == l && tr[k].r == r) return tr[k].sum;
 66     if (tr[k << 1].r >= r) return Query(k << 1, l, r);
 67     else if (tr[k << 1 | 1].l <= l) return Query(k << 1 | 1, l, r);
 68     else return (Query(k << 1, l, tr[k << 1].r) + Query(k << 1 | 1, tr[k << 1 | 1].l, r))%mod;
 69 }
 70 
 71 
 72 int bsearch(int x)
 73 {
 74     int l=1,r=tot,ans;
 75     while(l<=r){
 76         int mid=(l+r)>>1;
 77         if(c[mid]<=x) ans=mid,l=mid+1;
 78         else r=mid-1;        
 79     }
 80     return ans;
 81 }
 82 
 83 int main(){
 84     scanf("%d",&n);
 85     for(int i=1;i<=n;i++)
 86         scanf("%d%d",&p[i].x,&p[i].y),c[++cnt]=p[i].x,c[++cnt]=p[i].y;
 87     sort(c+1,c+1+cnt); c[0]=-1;
 88     for(int i=1;i<=cnt;i++)
 89         if(c[i]!=c[i-1]) c[++tot]=c[i];
 90     for(int i=1;i<=n;i++)
 91         p[i].x=bsearch(p[i].x),p[i].y=bsearch(p[i].y);
 92     sort(p+1,p+1+n);    
 93     int ans=n,sum=0,tmp=0;
 94     for(int i=1;i<=n;i++)
 95         if(p[i].y!=p[i-1].y){
 96             ans=(ans+(LL)sum*tmp)%mod;
 97             sum+=tmp; tmp=1;
 98         }
 99         else tmp++;    
100     ans=(ans+(LL)sum*tmp)%mod;
101     Build(1,1,tot);
102     for(int i=1;i<=n;i++)
103         s[p[i].x].push_back(p[i].y);
104     for(int i=tot;i>=1;i--){
105         int sz=s[i].size();        
106         for(int j=0;j<sz;j++){
107             int tmp1=Query(1,1,s[i][j]-1);
108             int tmp2=Query(1,s[i][j]+1,tot);
109             ans=(ans+(LL)tmp1*tmp2)%mod;
110         }
111         for(int j=0;j<sz;j++)
112             Insert(1,s[i][j]);
113     }
114     printf("%d",ans);
115     return 0;
116 }
View Code

 

J:plan

先全选3或全选2,然后考虑用2和3补满或退1间重新选

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
typedef long long LL;
 
long long n,p1,p2;
long long ans;
 
int main(){
    scanf("%lld%lld%lld",&n,&p1,&p2);
    LL tmp1,tmp2;
    tmp1=(n/2)*p1;
    tmp2=(n/3)*p2;
    if(n%2==1){
        LL tmp;
        tmp=min(p1,p2);
        if(tmp1) tmp=min(tmp,-p1+p2);
        tmp1+=tmp;
    }
    if(n%3==1){
        LL tmp;
        tmp=min(p1,p2);
        if(tmp2) tmp=min(tmp,-p2+p1+p1);
        tmp2+=tmp;
    }
    else if(n%3==2){
        LL tmp;
        tmp=min(p1,p2);
        tmp2+=tmp;
    }
    printf("%lld",min(tmp1,tmp2));
    return 0;
}
View Code

 

posted @ 2018-08-05 09:41  Hetui  阅读(155)  评论(0编辑  收藏  举报