18.8.24 考试总结

 

一开始我这道题竟然以为是最小费用最大流...怪我错误的预估了网络流的复杂度...。

然后把1mb记成了1e7...我已经被自己蠢死了cnm

这道题就是一个二分 + 贪心   先把所有的人和所有的钥匙从左到右排一边序

二分最大的限制时间是多少 然后就O(n)check是否合法

现在的问题就是如何check  那么对于每一把钥匙c 两个人a b

如果a拿钥匙合法 b拿钥匙则不一定合法 会更劣

所以从左往右扫的时候如果这个人能拿这个钥匙就拿 不能拿钥匙就换向右的下一把 看最终合法的人数是否等于n就可以了

代码

#include <bits/stdc++.h>
#define oo 1e9
using namespace std;
const int N = 1e5 + 5;
int n,m,ans = oo,k,b[N],a[N];
bool check(int lim) {
    
    int key = 1,p = 1;
    int num = 0;
    while(key <= m) {
        if(abs(k - b[key]) + abs(a[p] - b[key]) <= lim)
          p ++,num ++;
        if(num == n) break;
        key ++;
    }
    return num == n;
}
void solve( ) {
    
    int l = 1,r = oo;
    ans = oo;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid,r = mid - 1;
        else l = mid + 1;
    }
}
int main( ) {
    
    freopen("keys.in","r",stdin);
    freopen("keys.out","w",stdout);
    scanf("%d%d%d",& n,& m,& k);
    for(int i = 1;i <= n;i ++) scanf("%d",& a[i]);
    for(int i = 1;i <= m;i ++) scanf("%d",& b[i]);
    sort(a + 1,a + n + 1);
    sort(b + 1,b + m + 1);
    solve( );
    printf("%d",ans);
}

 

这道题就是一道裸的数据结构吧我觉得...

考试的时候还是调了一段时间

就线段树各种操作都搞一搞就可以了..。

我的query比较奇怪 就是乱搞搞某个区间的size 以及最小值的pos 

代码

#include <bits/stdc++.h>
#define oo 1e9
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n,a[N],nex[N],las[N],now;
ll ans;
struct node {
    
    int val,size,pos;
}f[4 * N];
inline int read( ) {
    
    int ans = 0,t = 1;
    char x; x = getchar( );
    while(x < '0' || x > '9') {
        if(x == '-') t = -1;
        x = getchar( );
    }
    while(x >= '0' && x <= '9') {
        ans = ans * 10 + x - '0';
        x = getchar( );
    }
    return ans * t;
}
void update(int o) {
    
    f[o].val = min(f[2 * o].val,f[2 * o + 1].val);
    f[o].size = f[2 * o].size + f[2 * o + 1].size;
    f[o].pos = f[2 * o].val <= f[2 * o + 1].val ? f[2 * o].pos : f[2 * o + 1].pos;
}
void build(int o,int l,int r) {
    
    if(l == r) {
        f[o].val = a[l];
        f[o].pos = l;
        f[o].size = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(2 * o,l,mid);
    build(2 * o + 1,mid + 1,r);
    update(o);
}
void modify(int o,int l,int r,int p) {
    
    if(l == r) {
        f[o].val = oo;
        f[o].pos = 0;
        f[o].size = 0;
        return ;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) modify(2 * o,l,mid,p);
    else modify(2 * o + 1,mid + 1,r,p);
    update(o);
}
node query(int o,int l,int r,int L,int R) {
    
    if(l >= L && r <= R) {
        return f[o];
    }
    int mid = (l + r) >> 1;
    node ans; ans.val = oo,ans.pos = 0,ans.size = 0;
    if(L <= mid) {
        node ll;  ll = query(2 * o,l,mid,L,R);
        ans.val = min(ans.val,ll.val);
        ans.pos = ll.pos; ans.size += ll.size;
    }
    if(mid < R) {
        node rr;  rr = query(2 * o + 1,mid + 1,r,L,R);
        if(ans.val > rr.val) ans.pos = rr.pos;
        ans.val = min(ans.val,rr.val);
        ans.size += rr.size;
    }
    return ans;
}
void solve( ) {
    
    now = 1;
    for(int i = 1;i <= n;i ++) {
        nex[i] = i + 1;
        if(i == n) nex[i] = 1;
        las[i] = i - 1;
        if(i == 1) las[i] = n;
    }
    int p;
    for(int i = 1;i <= n;i ++) {
        node np,qp;
        qp = query(1,1,n,now,n);
        if(now > 1){
            np = query(1,1,n,1,now - 1);
        }
        else np.val = oo,np.size = 0;
        node ss = query(1,1,n,1,now);
        if(qp.val > np.val) {
            p = np.pos;
            node s = query(1,1,n,1,np.pos);
            ans += (ll)f[1].size - (ll)(ss.size - s.size - 1);
        }
        else {
            p = qp.pos;
            node s = query(1,1,n,1,qp.pos);
            ans += (ll)(s.size - ss.size + 1);
        }
        modify(1,1,n,p); int pre = las[p];
        now = nex[p]; nex[pre] = now;
        las[now] = pre;
    }
}
int main( ) {
    
    freopen("cards.in","r",stdin);
    freopen("cards.out","w",stdout);
    n = read( );
    for(int i = 1;i <= n;i ++)
        a[i] = read( );
    build(1,1,n);
    solve( );
    printf("%I64d",ans);
}

 

第三题是一道整除分块的题

由题目可得 ∑(ai / d)上取整 * d - ai ≤ k 

昨天idy给我们讲了如何推出满足a / d 下取整= x的最大d

同样的 今天这道题是求得满足a / d上取整 = 某个值的最小d

所以就对d进行分块 讲a / d相等的分为一个快 因为这样子同一个块内d是满足二分性的

但是因为有多个a  所以就对所有小断点都分一下块

就像这样

可以进行二分来找最大的满足条件的d 因为将式子里的d提出来后 同一个块内的∑(ai / d)上取整是相同的

所以这个东西就变成了一个关于d的一次函数 就可以二分 二分朴素做法是O(n)判断 这道题是可以的 

但是有更优秀的O(1)判断 对于同一个块内 d的增减只会改变系数的个数 而系数是不变的 所以可以直接加上delta d * 系数

这样二分check时 复杂度就从n变成了1 (然而标程写的是O(n)check)

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 111;
int n;
long long k;
vector<long long> vc;
long long aa[N];
inline long long read( ) {
    
    long long ans = 0,t = 1;
    char x; x = getchar( );
    while(x < '0' || x > '9') {
        if(x == '-') t = -1;
        x = getchar( );
    }
    while(x >= '0' && x <= '9') {
        ans = ans * 10 + x - '0';
        x = getchar( );
    }
    return ans * t;
}
void split( long long a, vector<long long> &vc ) {
    vc.push_back(a);
    for(long long d = a;d;) {
        long long dd = (a + d - 1) / d;
        long long k = (a + dd - 1) / dd;
        vc.push_back(k);
        d = k - 1;
    }
}
bool check( long long d ) {
    long long sum = 0;
    for( int i = 1; i <= n; i++ ) {
        sum += (aa[i] + d - 1) / d * d - aa[i];
    }
    return sum <= k;
}
int main() {
    freopen("bamboo.in", "r", stdin);
    freopen("bamboo.out", "w", stdout);
    scanf("%d%I64d", &n, &k );
    for( int i = 1; i <= n; i++ ) {
        aa[i] = read( );
        split(aa[i],vc);
    }
    sort( vc.begin(), vc.end() );
    vc.erase(unique(vc.begin(),vc.end()),vc.end());
    vc.push_back( 10000000000000ll );
    long long ans = 1;
    for( int t = 0; t + 1 < (int)vc.size(); t++ ) {
        long long lf = vc[t];
        long long rg = vc[t+1] - 1;
        if( check(lf) == false ) continue;
        while( lf < rg ) {
            long long mid = (lf + rg + 1) >> 1;
            if( check(mid) )
                lf = mid;
            else
                rg = mid - 1;
        }
        ans = max( ans, lf );
    }
    printf( "%I64d\n", ans );
}

 

posted @ 2018-08-25 19:41  阿澈说他也想好好学习  阅读(181)  评论(0编辑  收藏  举报