【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】

Solution

 

注意取模!!!

Code

#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
using namespace std;

int n, a, b;

LL mpow(LL a, LL b) {
    LL ans = 1;
    for(; b; b >>= 1, a = a * a % mod)
        if(b & 1)    ans = ans * a % mod;
    return ans;
}

LL fac[200005], inv[200005], l[100005], t[100005];
void init() {
    fac[0] = 1;
    inv[0] = 1;
    for(int i = 1; i <= 200000; i ++) {
        fac[i] = fac[i - 1] * i % mod;
        inv[i] = mpow(fac[i], mod - 2);
    }
}

LL C(int p, int q) {
    return fac[p] * inv[q] % mod * inv[p - q] % mod;
}

int main() {
    freopen("matrix.in", "r", stdin);
    freopen("matrix.out", "w", stdout);
    scanf("%d%d%d", &n, &b, &a);
    for(int i = 1; i <= n; i ++)    scanf("%lld", &l[i]);
    for(int i = 1; i <= n; i ++)    scanf("%lld", &t[i]);
    LL ans = 0;
    init();
    for(int i = 2; i <= n; i ++) {
        ans = (ans + b * l[i] % mod * C(n - 2 + n - i, n - 2) % mod * mpow(a, n - i) % mod * mpow(b, n - 2) % mod) % mod;
        ans = (ans + a * t[i] % mod * C(n - 2 + n - i, n - 2) % mod * mpow(b, n - i) % mod * mpow(a, n - 2) % mod) % mod;
    }
    printf("%lld", ans);
    return 0;
}

Solution

二分+DP,二分需要多少组p+q,记忆化搜索判断是否可以达到条件。

定义$dp[dep][j][k]$表示当前取到第$dep$个数,还需要j个p,k个q来使满足条件。(p>q)

每次先尽量放p,剩下中再尽量放q,放q时就有限制,不能取超过$mid-i$,i表示当前取的p的数量。

Code

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

int n, a[55], p, q;
int sum[55], vis[55][1005][1005], tim, all;
bool dfs(int dep, int nump, int numq) {
    if(nump == 0 && numq == 0)    return 1;
    if(dep == n + 1 || sum[dep] < nump * p + numq * q)    return 0;
    if(vis[dep][nump][numq] == tim)    return 0;
    for(int i = 0; i <= min(nump, a[dep] / p); i ++)
        if(dfs(dep + 1, nump - i, max(numq - min((a[dep] - p * i) / q, all - i), 0)))    return 1;
    vis[dep][nump][numq] = tim;
    return 0;
}

bool check(int mid) {
    tim ++;
    all = mid;
    return dfs(1, mid, mid);
}

int erfen() {
    int l = 0, r = sum[1] / (p + q), ans;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid))    ans = mid, l = mid + 1;
        else    r = mid - 1;
    }
    return ans;
}

int main() {
    freopen("pq.in", "r", stdin);
    freopen("pq.out", "w", stdout);
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)    scanf("%d", &a[i]);
    for(int i = n; i >= 1; i --)    sum[i] = sum[i + 1] + a[i];
    scanf("%d%d", &p, &q);
    if(p < q)    swap(p, q);
    int ans = erfen();
    printf("%d", ans * (p + q));
    return 0;
}

 

Solution

考试最后半小时开始写QAQ结果发现是做过的题啊??

可是最后Spfa写错了!!!我爆哭!!!!

将与1相连的所有点取出来,二进制分类,分成起点和终点,跑多起点多终点的Spfa,处理出两两起点终点间最短路,更新答案即可QAQ

Spfa要判更新的点不能是1!!

Code

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

int n, m;

struct Node {
    int v, nex, w;
} Edge[200005];

int h[30005], stot = 1;
void add(int u, int v, int w) {
    Edge[++stot] = (Node) {v, h[u], w};
    h[u] = stot;
}

int dis[30005];
int vis[30005], nums, numt, w[30005], t[30005], S[30005], T[30005];
void Spfa1() {
    queue < int > q;
    memset(vis, 0, sizeof(vis));
    memset(dis, 0x3f3f3f3f, sizeof(dis));
    for(int i = 1; i <= nums; i ++)    q.push(S[i]), vis[S[i]] = 1, dis[S[i]] = min(dis[S[i]], w[S[i]]);
    while(!q.empty()) {
        int u = q.front();    q.pop();    vis[u] = 0;
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(dis[v] > dis[u] + Edge[i].w && v != 1) {
                dis[v] = dis[u] + Edge[i].w;
                if(!vis[v]) {
                    vis[v] = 1;    q.push(v);
                }
            }
        }
    }
}

void Spfa2() {
    queue < int > q;
    memset(vis, 0, sizeof(vis));
    memset(dis, 0x3f3f3f3f, sizeof(dis));
    for(int i = 1; i <= numt; i ++)    q.push(T[i]), vis[T[i]] = 1, dis[T[i]] = min(dis[T[i]], w[T[i]]);
    while(!q.empty()) {
        int u = q.front();    q.pop();    vis[u] = 0;
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(dis[v] > dis[u] + Edge[i].w && v != 1) {
                dis[v] = dis[u] + Edge[i].w;
                if(!vis[v]) {
                    vis[v] = 1;    q.push(v);
                }
            }
        }
    }
}

int tov[30006], tot;
int main() {
    freopen("graph.in", "r", stdin);
    freopen("graph.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++) {
        int u, v, a, b;
        scanf("%d%d%d%d", &u, &v, &a, &b);
        add(u, v, a);    add(v, u, b);
    }
    int ans = 0x3f3f3f3f;
    memset(w, 0x3f3f3f3f, sizeof(w));
    memset(t, 0x3f3f3f3f, sizeof(t));
    for(int i = h[1]; i; i = Edge[i].nex)
        tov[++tot] = Edge[i].v, w[Edge[i].v] = min(w[Edge[i].v], Edge[i].w), t[Edge[i].v] = min(t[Edge[i].v], Edge[i ^ 1].w);
    sort(tov + 1, tov + 1 + tot);
    int M = tov[tot], tt = 0;
    while(M) {
        int tmp = (M & 1);
        nums = 0, numt = 0;
        for(int i = 1; i <= tot; i ++)
            if(((tov[i] >> tt) & 1) == tmp)    S[++nums] = tov[i];
            else    T[++numt] = tov[i];
        Spfa1(); 
        for(int j = 1; j <= numt; j ++) {
            ans = min(ans, t[T[j]] + dis[T[j]]);
        }
        Spfa2();
        for(int j = 1; j <= nums; j ++) {
            ans = min(ans, t[S[j]] + dis[S[j]]);
        }
        M >>= 1, tt ++;
    }
    printf("%d", ans);
    return 0;
}

 

posted @ 2018-10-31 15:35  Wans_ovo  阅读(188)  评论(0编辑  收藏  举报