四校联考【20171001】

T1

[二分]

期望得分:70

实际得分:10

枚举最高的高度可能为多少+二分。O(logm)

枚举最高高度应该位于哪一列上.O(n)

左右扩散枚举出需要用的积木总数,与m相比较。

容易发现合法的高度的最高值,最终需要搭建一个金字塔。

1,3,5,7…                        

 

正解是预处理出每一列作为最高列的左右边界。

然后再二分最大高度。

Check出每个数是否合法即可。

 

考场做法的错误在于:并不要堆成完全的金字塔形状。

 


例如上图,其实只需要绿色部分就够了。

居然这么还能苟到10分。。

但是离正解很近了啊啊啊。

【code】

#include<bits/stdc++.h>
using namespace std; 
#define ll long long 
#define File "block"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline int read(){
    int x = 0,f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
    return x*f;
}
const int mxn = 1e5 + 5;
int n,m;
int a[mxn];
int L[mxn],R[mxn];
int mx;
ll s[mxn];

inline bool check(int h){
    int l = n,r = 1;
    for(int i = n;i >= 1; --i){
        while(a[l] < h-(i-l) && l >= 1) l--;
        L[i] = l;
    }
    for(int i = 1;i <= n; ++i){
        while(a[r] < h-(r-i) && r <= n) r++;
        R[i] = r;
    }
    
    for(int i = 1;i <= n; ++i){
        ll p,q,t;
        if(L[i] < 1 || R[i] > n) continue; 
        p = h-(i-L[i]),q = h-(R[i]-i);
        t = 1ll*h*h-1ll*(p+1)*p/2-1ll*(q+1)*q/2-(s[R[i]-1]-s[L[i]]);
        if(t <= m) return true;        
    }
    return false;
}

int main(){
    file();
    n = read(),m = read();
    for(int i = 1;i <= n; ++i) a[i] = read(),mx = max(mx,a[i]),s[i] = s[i-1]+(ll)a[i];
    
    int l = mx+1,r = (int)(sqrt(m)+1)+mx+1;
    while(l < r){
        int mid = (l+r) >>1;
        if(check(mid)) l = mid+1;
        else r = mid;
    }
    printf("%d\n",l-1);
    return 0;
}
/*
8 4
3
4
2
1
3
3
2
4
*/
/*
3 100
3
3
3
*/
View Code

 

T2

[贪心,链表]

期望得分:30

实际得分:0

知道是个贪心。对于每个n[i],贪心选择较大的前n[i]个m[i]减去1。

正解做法是对贪心进行优化。

 

正解的链表做法好玄妙好棒哦。

能这么做是因为值域就在[1,m]范围内,而且每次变化就在相邻的两个元素之间。

这样可以用链表快速维护相邻两个数的关系。

据说还有网络流的写法。不想写。我不会。

 【code】

#include<bits/stdc++.h>
using namespace std; 
#define ll long long 
#define File "cake"
inline void file(){
    freopen(File".in","r",stdin);
    freopen(File".out","w",stdout);
}
inline int read(){
    int x = 0,f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch=='-')f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();}
    return x*f;
}
const int mxn = 2.5*1e6 + 19;
int m,n,md,nd,m0,n0;
inline bool cmp(int x,int y){
    return x > y;
}
int X[mxn],Y[mxn];
int L[mxn],R[mxn];

inline void del(int x){
    L[R[x]] = L[x];
    R[L[x]] = R[x];
} 
int main(){
    file();
    m = read(),n = read(),m0 = read(),md = read(),n0 = read(),nd = read();
    X[m0]++,Y[n0]++;    
    for(int i = 1;i < m; ++i)
        m0 = (m0*58+md)%(n+1),X[m0]++;
    for(int i = 1;i < n; ++i)
        n0 = (n0*58+nd)%(m+1),Y[n0]++;

    for(int i = 1;i < max(n,m)+9; ++i)        
        L[i] = i+1,R[i] = i-1;//从大到小链接 
    
    int cur = m,s(0);
    ll ans(0);
    for(int i = n; i; --i){
        while(X[i] && cur){
            --X[i];
            while(s < i && R[cur]){
                s += Y[cur];
                cur = R[cur];
            }
            while(s >= i+Y[cur]){
                s -= Y[cur];
                cur = L[cur];
            }
            ans += (ll)min(i,s);
            if(s > i){
                int x = Y[cur] - (s-i);
                if(R[cur]) Y[R[cur]] += x;
                s -= x;
                Y[cur] += Y[L[cur]] - x;
                del(L[cur]);
            }else{
                s -= Y[cur];
                if(R[cur]) Y[R[cur]] += Y[cur];
                del(cur);
                cur = L[cur];
            } 
        }
    }    
    printf("%d\n",ans); 
                
    return 0;
} 
/*
5 8 1 2 3 4
*/
View Code

 

T3

[树形dp]

可能的得分:30

实际得分:0

暴力就是看图模拟吧。但是没写就是了。

 

整体总结:

状态不佳。。。不给自己找客观原因吧。

posted @ 2019-08-12 20:30  ve-2021  阅读(169)  评论(0编辑  收藏  举报