Wannafly挑战赛15

标签: nowcoder


传送门

https://www.nowcoder.com/acm/contest/112#question

A.最小化价格

贪心做的。贪心策略:从价格最低的开始分配,然后对于每个地点把它所能容纳的最大的队伍分配给他。(PS:看到钰神的贪心策略是这样的,从人数最多的队伍开始分配,每次把能够容纳这个队伍的价格最低的分配给他,优先队列就可以实现)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
const int maxn=200050;
typedef long long ll;
const ll MOd=1e9+7;
struct node{
    int x,p;
    bool operator <(const node&y)const{
        if(p!=y.p) return p<y.p;
        return x>y.x;
    }
}b[maxn];
int a[maxn];
bool cmp(int a,int b){
    return a>b;
}
map<int,int> mp;
int main(){
    int n,m;
    scanf("%d%d", &n,&m);
    int M=0;
    for(int i = 0; i < n; ++i){
        int x;
        scanf("%d", &x);
        M=max(M,x);
        mp[x]++;
    }
    for(int i = 0; i < m; ++i){
        scanf("%d%d", &b[i].x,&b[i].p);
    }
    sort(b,b+m);
    int sum=0;
    for(int i = 0; i < m; ++i){
        map<int,int>::iterator it=mp.lower_bound(b[i].x);
        if(it->first == b[i].x) it->second --,sum+=b[i].p;
        else if(it==mp.begin()) continue;
        else{
            it--;
            it->second --;
            sum+=b[i].p;
        }
        if(it->second == 0){
            mp.erase(it);
        }
    }
    if(mp.size()) cout << -1 << endl;
    else cout << sum << endl;
}

B.车辆安排

#include <iostream>
#include <cstdio>
using namespace std;
int a[10];
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i){
        int x;
        scanf("%d", &x);
        a[x]++;
    }
    int ans=a[5];
    if(a[1]>a[4]) a[1]-=a[4],ans+=a[4],a[4]=0;
    else a[1]=0,ans+=a[4],a[4]=0;
    if(a[2]>a[3]) a[2]-=a[3],ans+=a[3],a[3]=0;
    else{
        ans+=a[2],a[3]-=a[2],a[2]=0;
        if(a[1]>2*a[3]) ans+=a[3],a[1]-=2*a[3],a[3]=0;
        else ans+=a[3],a[1]=0,a[3]=0;
    }
    if(2*a[1]<a[2]){
        ans+=a[1];
        a[2]-=a[1]*2;
        a[1]=0;
    }
    else{
        ans+=a[2]/2;
        a[1]-=a[2]/2;
        a[2]-=a[2]/2*2;
    }
    if(a[2]&&a[1]==0){
        ans+=(a[2]+1)/2;
    }
    else{
        int x=a[1]+a[2]*2;
        ans+=(x/5);
        if(x%5) ans++;
    }
    cout << ans <<endl;
}

C.出队

递归模拟即可,时间复杂度\(O(log_2x)\)

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll f(ll n,ll x){
    if(x&1) return (x+1)/2;
    ll y=x/2-1;
    if(y==0) y=n/2;
    if(n&1) return n/2+1+f(n/2,y);
    return n/2+f(n/2,x/2);
}
int main(){
    ll n,q;
    scanf("%lld%lld", &n,&q);
    while(q--){
        ll x;
        scanf("%lld", &x);
        cout << f(n,x) << endl;
    }
    return 0;
}

D.数字串

对于每个数字都建立一个树状数组,每次修改时先减去他的影响,再加上新数的影响。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=100050;
int a[10][maxn],n;
void update(int *p,int x,int val){
    while(x<=n){
        p[x]+=val;
        x += x&-x;
    }
}
int query(int *p,int x){
    int ans=0;
    while(x){
        ans+=p[x];
        x-=x&-x;
    }
    return ans;
}
char s[maxn];
int main(){
    scanf("%s", s+1);
    n=strlen(s+1);
    int q,l,r;
    scanf("%d%d%d", &q,&l,&r);
    ll sum=0;
    for(int i = n; i >= 1; --i){
        update(a[s[i]-'0'],i,1);
        for(int j = 0; j < s[i]-'0'; ++j){
            sum+=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
        }
    }
    while(q--){
        int i,x;
        scanf("%d%d", &i,&x);
        int y=s[i]-'0';
        s[i]=x+'0';
        for(int j = 0; j < y; ++j){
            sum-=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
        }
        for(int j = 9; j > y; --j){
            sum-=query(a[j],max(i-l+1,0))-query(a[j],max(0,i-r));
        }
        update(a[y],i,-1);
        for(int j = 0; j < x; ++j){
            sum+=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
        }
        for(int j = 9; j > x; --j){
            sum+=query(a[j],max(i-l+1,0))-query(a[j],max(0,i-r));
        }
        update(a[x],i,1);
        printf("%lld\n", sum);
    }
    return 0;
}

E.小W的斜率

分析

  我们要求两个点连线斜率最接近\(P/Q\)的。可以考虑这样,在\((Q,P)\)方向和\((P,-Q)\)建立新的坐标轴,那么沿着\((P,-Q)\)方向排列所有的点,排列后相邻的点之间的连线的斜率一定是最接近\(P/Q\)的。

#include <iostream>
#include <cstdio>
#include <algorithm>
 
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int maxn=1000050;
int n,p,q;
struct node{
    int x,y;
    bool operator < (const node&t)const{
        return (ll)p*x-(ll)q*y<(ll)p*t.x-(ll)q*t.y;
    }
}a[maxn];
int main(){
    scanf("%d%d%d", &n,&p,&q);
    for(int i = 0; i < n; ++i) scanf("%d%d", &a[i].x,&a[i].y);
    sort(a,a+n);
    double m=1e20;
    int P,Q;
    for(int i = 1; i < n; ++i){
        double t=(double)(a[i].y-a[i-1].y)/(double)(a[i].x-a[i-1].x)-(double)p/q;
        if(fabs(t)<m){
            m=fabs(t);
            P=a[i].y-a[i-1].y;
            Q=a[i].x-a[i-1].x;
        }
    }
    
    if(P<0) P=-P,Q=-Q;
    int d=__gcd(P,Q);
    P/=d,Q/=d;
    printf("%d/%d\n", P,Q);
}

F.下棋

留坑

posted @ 2018-05-12 23:00  sciorz  阅读(212)  评论(0编辑  收藏  举报