题目链接:https://www.nowcoder.com/acm/contest/18#question


A:考虑到均分一定比不均分好,我们就容易反推回去了。

#include <bits/stdc++.h>
using namespace std;
int work(int n, int cnt){
    vector <int> q(cnt, n/cnt);
    for(int i=0; i<n%cnt; i++) q[i]++;
    int s = 0;
    for(int i=0,p=0,sz=q.size(); i<sz; i++) s+=p*q[i], p+=q[i];
    return s;
}
int main(){
    int n, m;
    scanf("%d %d", &n,&m);
    int i;
    for(i=2; i<=n; i++) if(work(n,i)>=m) break;
    return 0*printf("%d\n", i==n+1?-1:i-1);
    return 0;
}

D:直接二进制枚举哪些是加完要重排的,然后DFS即可。复杂度10!*32
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, x, ans, a[10];
LL sum;
void dfs(int dep, LL now, bool vis[]){
    if(dep==n){
        sum = max(sum, now);
        return;
    }
    if(vis[dep]){
        LL x = now+a[dep];
        vector <int> v;
        LL tmp = x;
        while(x){
            v.push_back(x%10);
            x/=10;
        }
        sort(v.begin(),v.end());
        do{
            LL t = 0;
            for(LL i=0; i<v.size(); i++){
                 t = t*10 + v[i];
            }
            dfs(dep+1, t, vis);
        }while(next_permutation(v.begin(),v.end()));
    }
    else dfs(dep+1, now+a[dep], vis);
}
int main(){
    scanf("%lld", &n);
    ans = 0;
    for(LL i=0; i<n; i++) scanf("%lld", &a[i]);
    LL mask = (1<<n);
    for(LL i=0; i<mask; i++){
        bool vis[10]={0};
        for(LL j=0; j<n; j++){
            if(i&(1<<j)) vis[j]=1;
        }
        sum = 0;
        dfs(0, 0, vis);
        ans = max(ans, sum);
    }
    printf("%lld\n", ans);
    return 0;
}

E:我们假如每次都刷一个木板,即一竖行,那么需要n次刷完,可见这是一个ans的最大值。就是最差的情况下我这样刷最多为n刷。如果我们选择一横行的刷,而n个木板中最短的为mi,那么我们可以花min刷,把他们都刷成a [ i ] - mi的高度,那么剩下来的栅栏又变成了开始的情况,我们可以在选择前面不为0的x个,继续按上面的方法刷,可见是一个递归调用即可。要特别注意的是前面的条件,就是刷x个木板,最多用x刷,如果某一次求得大于x,那么取x。


#include <bits/stdc++.h>
using namespace std;
const int maxn = 5010;
int n, a[maxn], tmp;
void gao(int l, int r){
    int mx = -1, mi = INT_MAX;
    for(int i=l; i<r; i++){
        mx = max(mx, a[i]);
        mi = min(mi, a[i]);
    }
    if(mx == mi){
        tmp += min(mx, r-l);
        return;
    }
    for(int i=l; i<r; i++) a[i] -= mi;
    mi = min(mi, r-l);
    tmp += mi;
    for(int i=l; i<r; i++){
        if(a[i]>0){
            for(int j=i; j<r; j++){
                if(a[j]==0||(j==(r-1)&&a[j]>0)){
                    if(j==(r-1)&&a[j]>0) j++;
                    int temp2 = tmp;
                    gao(i, j);
                    if(tmp-temp2>(j-i)){//判断如果求得的值比直接一行一行刷更大的话,取更小的
                        tmp = temp2+(j-i);
                    }
                    i=j;
                    break;
                }
            }
        }
    }
}
int main(){
    scanf("%d", &n);
    for(int i=0; i<n; i++) scanf("%d", &a[i]);
    tmp = 0;
    gao(0, n);
    return 0*printf("%d\n", min(tmp, n));
}