1. 程式人生 > >“Wishare杯”南郵第八屆大學生程式設計競賽之網路預賽 題解報告

“Wishare杯”南郵第八屆大學生程式設計競賽之網路預賽 題解報告

對於第二組樣例

第一個人可以以(1,1) -> (2,1) -> (2, 2) -> (3,2) -> (3,3)的順序說服5個妹子

第二個人的順序可以是(1, 1) -> (2, 1) -> (3, 1),因為(1,1) (2,1)位置的妹子已經被說服了,他這一輪只說服了一個妹子。

兩輪下來所有妹子都被說服,因此總顏值就是她們的顏值和為21

題目分析:最大費用最大流,超源連起點,終點連超匯,費用為0,容量為k,有權值的點拆點鍵圖,拆完點兩條邊一條費用為權值,容量為1保證取值,另一條費用為0,容量無窮大保證可重複走,然後跑個費用流~

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
int const INF = 0x3fffffff;
int const MAX = 26 * 26;
int n, k;
int head[MAX << 2], cnt;
int pre[MAX << 2], vis[MAX << 2];
int src, sk;
ll ans, a[30][30], dis[MAX << 2];

struct EGDE
{
    int to, nxt, cap;
    ll cost;
}e[MAX << 3];

void Init()
{
    ans = 0;
    src = 0;
    sk = 2 * n * n + 1; 
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void Add(int u, int v, int cap, ll cost)
{
    e[cnt].to = v;
    e[cnt].cap = cap;
    e[cnt].cost = cost;
    e[cnt].nxt = head[u];
    head[u] = cnt ++;

    e[cnt].to = u;
    e[cnt].cap = 0;
    e[cnt].cost = -cost;
    e[cnt].nxt = head[v];
    head[v] = cnt ++;
}

void Build_graph()
{
    Add(src, 1, k, 0);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= i; j++)
        {
            Add((i - 1) * n + j, n * n + (i - 1) * n + j, 1, a[i][j]);
            Add((i - 1) * n + j, n * n + (i - 1) * n + j, INF, 0);
            if(j < n)
                Add(n * n + (i - 1) * n + j, (i - 1) * n + j + 1, INF, 0);
            if(i < n)
                Add(n * n + (i - 1) * n + j, i * n + j, INF, 0);
        }
    }
    Add(2 * n * n, sk, k, 0);
}

bool SPFA()
{
    memset(vis, false, sizeof(vis));
    memset(dis, -1, sizeof(dis));
    memset(pre, -1, sizeof(pre));
    queue <int> q;
    q.push(src);
    vis[src] = true;
    dis[src] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = e[i].nxt)
        {
            int v = e[i].to;
            int cap = e[i].cap;
            ll cost = e[i].cost;
            if(cap > 0 && dis[v] < dis[u] + cost)
            {
                dis[v] = dis[u] + cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return dis[sk] != -1;
}

void Augment()
{
    int mi = INF;
    while(SPFA())
    {
        for(int i = sk; i != src; i = e[pre[i] ^ 1].to)
            mi = min(mi, e[pre[i]].cap);
        for(int i = sk; i != src; i = e[pre[i] ^ 1].to)
        {
            ans += (ll)mi * e[pre[i]].cost;
            e[pre[i]].cap -= mi;
            e[pre[i] ^ 1].cap += mi; 
        }
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d %d", &n, &k);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= i; j++)
                scanf("%I64d", &a[i][j]);
        Init(); 
        Build_graph();
        Augment();
        printf("%I64d\n", ans);
    }
}

文科生or理科生

                                                                                時間限制(普通/Java):1000MS/3000MS         執行記憶體限制:32768KByte


題目分析:首先an通過做差得到an = n^2 + 3n + 1 = (n + 2) * (n + 1) - 1,分母提出一個根號n,就是(根號n) * (n + 1)!,分子就是(i + 2)! - (i)!求和,這個高中生都會吧?錯位相減,最後再化簡可以把分子上的階乘約掉,至於分母上的,只保留6位小數。。。自己感受去吧

#include <cstdio>
#include <cmath>

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        double n;
        scanf("%lf", &n);
        if(n >= 20)
            printf("%.6f\n", (n + 3.0) / sqrt(n));
        else
        {
            double f = 1.0;
            for(int i = 2; i <= n + 1; i++)
                f = f * i * 1.0;
            printf("%.6f\n",  (n + 3.0 - 3.0 / f) / sqrt(n));
        }
    }
}