Petrozavodsk WinterTraining 2015

PetrozavodskWinterTraining2015

A - Three Servers

題目描述:有\(n\)個數,將這\(n\)個數分紅\(3\)堆,使得\(3\)堆中和的最大值減最小值最小,求方案。c++

solution
\(f[i][j]\)表示第二堆減第一堆等於\(i\),第三堆減第二堆等於\(j\)的方案。因爲數字比較小,因此能夠定\(-100 \leq i, j \leq 100\),而後將讀入數據隨機排序,作\(10\)次就能夠過了。socket

時間複雜度:\(O(能過)\)spa

F - Empty Vessels

題目描述:有\(n\)個水杯,每一個水杯的容量爲\(a_i\),如今有\(3\)種操做:rest

  1. 將某個水杯裝滿水
  2. 將某個水杯裏的水倒掉
  3. 將某個水杯裏的水倒到另外一個水杯裏,直到一個水杯滿或一個水杯空
    給定一個值\(m\),問是否經過若干次操做以後某個水杯裏的水體積爲\(m\),求出方案。

solution
顯然,\(m\)必定要是\(a_i\)的最大公約數的倍數,而且\(m\)要小於\(a_i\)的最大值。
而後將最大的水杯看作剩餘系,全部水杯往最大的水杯倒水,至關於水量模最大水杯容量,而後像徹底揹包那樣作便可。code

時間複雜度:\(O(最大容量*n)\)server

G - Maximum Product

solution排序

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn=30;

LL A, B;
int a[maxn], b[maxn], now[maxn];

void calc(LL num, int *a)
{
    if (num==0) a[a[0]=1]=0;
    a[0]=0;
    while (num)
    {
        a[++a[0]]=num%10;
        num/=10;
    }
}
bool check()
{
    if (now[0]!=a[0]) return now[0]>a[0];
    for (int i=now[0]; i; --i)
        if (now[i]!=a[i]) return now[i]>a[i];
    return true;
}
void solve()
{
    scanf("%lld%lld", &A, &B);
    calc(A, a);
    calc(B, b);

    LL answer=1, ans=B;
    for (int i=1; i<=b[0]; ++i) answer*=b[i];

    for (int i=b[0]; i; --i)
    {
        for (int j=b[0]; j>i; --j) now[j]=b[j];
        now[i]=b[i]-1;
        for (int j=i-1; j; --j) now[j]=9;
        for (int j=i; j<b[0]; ++j)
            if (now[j]<0)
            {
                now[j]+=10;
                now[j+1]--;
            }
            else break;
        now[0]=b[0];
        if (now[0]>1 && now[now[0]]==0) --now[0];
        if (check())
        {
            LL s=1;
            for (int j=1; j<=now[0]; ++j) s*=now[j];
            if (s>answer)
            {
                answer=s;
                ans=0;
                for (int j=now[0]; j; --j) ans=ans*10+now[j];
            }
        }
    }
    printf("%lld\n", ans);
}
int main()
{
    solve();
    return 0;
}

H - Biathlon 2.0

題目描述:分別給定\(n, m\)個向量,對於\(n\)裏面的每一個向量,在\(m\)中找一個向量,使得兩個向量的點乘最小。three

solution
根據點乘的意義,至關因而一個向量在另外一個向量的投影,所以能夠想到只有\(m\)個向量造成的下凸殼,在下凸殼上的點纔是答案,將\(n\)個向量極角排序,而後每一個向量對應的答案在下凸殼上是單調的。it

時間複雜度:\(O(nlogn)\)io

I - Archaeological Research

題目描述:有一個未知序列\(a_i\),給出一些數據,第\(i\)行第\(j\)個數據表示某個數在序列的第\(i+1\)個數後面(包括\(i+1\))第一次出現的位置是\(j\),找出\(a_i\)的可行解中字典序最小的一個。

solution
題目還能夠用另外一種方式表達:第\(i\)行第\(j\)個數據表示某個數在序列的第\(i+1\)位到第\(j-1\)位沒出現過,進而能夠求出\(a_i\)\([l_i, i-1]\)沒出現過,而後只要貪心地從左到右放數,每次取\([1, l_i-1]\)中最小的數,若是\(l_i=1\),那麼新開一個數字給\(a_i\)

時間複雜度:\(O(nlogn)\)

J - Sockets

題目描述:有一個電源(只有一個插座),\(n\)個排插,分別有\(a_i\)個插座,每一個排插能夠直接接電源或者插到別的排插上,有\(m\)部手機須要同時充電,每部手機規定到電源之間最多能有\(b_i\)個排插,問最多能有多少部手機同時充電。

solution
將排插按\(a_i\)從大到小排序,手機按\(b_i\)從小到大排序,二分答案,先知足\(b_i\)較小的,其它位置插排插。

時間複雜度:\(O(nlogn)\)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn=int(2e5)+100;

int n, m;
int a[maxn], b[maxn];


void read()
{
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
    for (int i=1; i<=m; ++i) scanf("%d", &b[i]);
}
bool check(int num)
{
    LL rest=1;
    for (int i=1, level=0; i<=n && num; ++level)
    {
        int k=num;
        while (k && b[k]==level) --k;
        if (num-k>rest) return false;
        LL tmp=(rest-=(num-k));
        num=k;
        while (i<=n && (tmp--)) rest+=a[i++]-1;
    }
    return rest>=num;
}
void solve()
{
    sort(a+1, a+1+n, greater<int>());
    sort(b+1, b+1+m, greater<int>());

    int L=0, R=m+1;
    while (L+1<R)
    {
        int mid=(L+R)>>1;
        if (check(mid)) L=mid;
        else R=mid;
    }
    printf("%d\n", L);
}
int main()
{
    read();
    solve();
    return 0;
}

K - Toll Roads

題目描述:給定一棵樹,邊權爲\(1\),如今能夠選擇一條長度不超過\(m\)的鏈,將鏈上的邊權全改成\(0\),使得樹的直徑最小,求方案。

solution
思路挺好想的,就是枚舉一端做爲樹根,而後相似樹形\(dp\)算出當另外一端某個點時,樹的直徑是多少。

時間複雜度:\(O(n^2)\)

#include <bits/stdc++.h>
using namespace std;

const int maxn=5010;

int n, m, root;
vector<int> out[maxn];
int idx[maxn];
pair<int, int> le[maxn], ri[maxn];
int radle[maxn], radri[maxn];
int fa[maxn], f[maxn], g[maxn], h[maxn];
int rad[maxn], deep[maxn];
pair<int, int> ans, solu;

void read()
{
    scanf("%d%d", &n, &m);
    for (int i=0; i<n; ++i) out[i].clear();
    for (int i=1; i<n; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        out[u].push_back(v);
        out[v].push_back(u);
    }
}
void dfs1(int cur, int _fa)
{
    rad[cur]=0;
    f[cur]=0;
    fa[cur]=_fa;
    if (_fa==-1) deep[cur]=0;
    else deep[cur]=deep[_fa]+1;
    for (auto &to:out[cur])
    if (to!=_fa)
    {
        dfs1(to, cur);
        rad[cur]=max(rad[cur], max(rad[to], f[cur]+f[to]+1));
        f[cur]=max(f[cur], f[to]+1);
    }
}
void dfs2(int cur, int past, int chain)
{
    if (deep[cur]>m) return;
    int s=max(past, max(rad[cur], chain+f[cur]));
    if (make_pair(s, deep[cur])<ans)
    {
        ans=make_pair(s, deep[cur]);
        solu=make_pair(root, cur);
    }
    int cnt=0;
    for (auto &to:out[cur])
        if (to!=fa[cur]) idx[++cnt]=to;
    le[1]=make_pair(0, 0);
    radle[1]=0;
    for (int i=2; i<=cnt; ++i)
    {
        le[i]=le[i-1];
        radle[i]=max(radle[i-1], rad[idx[i-1]]);
        if (f[idx[i-1]]+1>le[i].first)
        {
            le[i].second=le[i].first;
            le[i].first=f[idx[i-1]]+1;
        }
        else le[i].second=max(le[i].second, f[idx[i-1]]+1);
    }
    ri[cnt]=make_pair(0, 0);
    radri[cnt]=0;
    for (int i=cnt-1; i>0; --i)
    {
        ri[i]=ri[i+1];
        radri[i]=max(radri[i+1], rad[idx[i+1]]);
        if (f[idx[i+1]]+1>ri[i].first)
        {
            ri[i].second=ri[i].first;
            ri[i].first=f[idx[i+1]]+1;
        }
        else ri[i].second=max(ri[i].second, f[idx[i+1]]+1);
    }
    for (int i=1; i<=cnt; ++i)
    {
        g[idx[i]]=max(le[i].first, ri[i].first);
        h[idx[i]]=max(le[i].first+ri[i].first, max(le[i].first+le[i].second, ri[i].first+ri[i].second));
        h[idx[i]]=max(h[idx[i]], max(radle[i], radri[i]));
    }
    for (auto &to:out[cur])
        if (to!=fa[cur]) dfs2(to, max(past, max(h[to], chain+g[to])), max(chain, g[to]));
}
void solve()
{
    ans=make_pair(n*2, 0);
    for (int i=0; i<n; ++i)
    {
        root=i;
        dfs1(i, -1);
        dfs2(i, 0, 0);
    }
    printf("%d\n%d\n", ans.first, ans.second);
    if (ans.second) printf("%d %d\n", solu.first, solu.second);
}
int main()
{
    read();
    solve();
    return 0;
}
相關文章
相關標籤/搜索