8.20模拟赛 [POI2009]WIE-Hexer [Lydsy1708月赛]跳伞求生 51nod 1479 小Y的数论题

版权声明:_ https://blog.csdn.net/lunch__/article/details/81874699

 T1

发现 p 很小,在最短路的基础上再加一维表示一个二进制数,代表当前拥有的剑的种类数,直接用 S P F A 就可以过了

Codes

#include<bits/stdc++.h>

#define pb push_back

using namespace std;

const int N = 200 + 10;
vector<int> G[N], v[N], w[N];
int n, m, p, k, val[N];
int dis[N][1 << 13], vis[N][1 << 13], ans = INT_MAX;

void Init() {
    int x, y, z, t;
    scanf("%d%d%d%d", &n, &m, &p, &k);
    for(int i = 1; i <= k; ++ i) {
        scanf("%d%d", &x, &y);
        for(int j = 1; j <= y; ++ j) {
            scanf("%d", &z);
            val[x] |= (1 << (z - 1));
        }
    }
    for(int i = 1; i <= m; ++ i) {
        int sum = 0;
        scanf("%d%d%d%d", &x, &y, &z, &t);
        G[x].pb(y), v[x].pb(z);
        G[y].pb(x), v[y].pb(z);
        for(int j = 1; j <= t; ++ j) {
            scanf("%d", &z);
            sum |= (1 << (z - 1));
        }
        w[x].pb(sum), w[y].pb(sum);
    }
}

void SPFA() {
    for(int i = 1; i <= n; ++ i)
        for(int j = 0; j < (1 << p); ++ j)
            dis[i][j] = 1e9 + 9, vis[i][j] = 0;
    queue<int> q1, q2; q1.push(1), q2.push(val[1]);
    dis[1][val[1]] = 0, vis[1][val[1]] = 1;
    while(!q1.empty()) {
        int x1 = q1.front(), x2 = q2.front();
        q1.pop(); q2.pop();
        for(int j = 0, sz = G[x1].size(); j < sz; ++ j) {
            int y1 = G[x1][j], y2 = x2 | val[y1];
            if((x2 & w[x1][j]) >= w[x1][j] && dis[y1][y2] > dis[x1][x2] + v[x1][j]) {
                dis[y1][y2] = dis[x1][x2] + v[x1][j];
                if(!vis[y1][y2]) {
                    q1.push(vis[y1][y2] = y1);
                    q2.push(y2);
                }
            }
        }
        vis[x1][x2] = 0;
    }
    for(int j = 0; j < (1 << p); ++ j)
        ans = min(ans, dis[n][j]);
    printf("%d\n", ans == 1e9 + 9 ? -1 : ans);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("dalao.in", "r", stdin);
    freopen("dalao.out", "w", stdout);
#endif
    Init();
    SPFA();
    return 0;
}

T2

神奇的贪心,正解做法太神仙了,反正贪心也是对的

首先把房间按 c b 从大到小排序,把 a 放进一个 m u l t i s e t 里,遍历房间,先确定房间的最大匹配数 k ,并把能匹配的房间取出来,然后把 a 最大的 k 个数取出来,每次尝试把最大的 a 和最大的 c b 加入答案,可以发现 a + c b > 0 时答案会更优,这样子就做完了。
正确性的话,由匹配的方式可知最后房间的序列的每一个前缀都一定能对应上 a 的一个匹配,那么直接取 a 最大的几个一定不会更劣,由于每一个前缀都有对应,直接枚举前缀长度就好了,复杂度 O ( n l o g n )


#include<bits/stdc++.h>

#define int long long

using namespace std;

const int N = 1e5 + 10;
int n, m, a[N], cnt;

struct node {
    int b, c, val, fuck;
}A[N], tmp[N];

bool cmp(node x, node y) {
    if(x.val == y.val) return x.b > y.b;
    return x.val > y.val;
}

multiset<int> S;
multiset<int>::iterator it;

signed main() {
#ifndef ONLINE_JUDGE
    freopen("winner.in", "r", stdin);
    freopen("winner.out", "w", stdout);
#endif
    int ans = 0;
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; ++ i) {
        scanf("%lld", &a[i]);
        S.insert(a[i]);
    }
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= m; ++ i) {
        scanf("%lld%lld", &A[i].b, &A[i].c);
        A[i].val = A[i].c - A[i].b;
    }
    sort(A + 1, A + m + 1, cmp);
    for(int i = 1; i <= m; ++ i) {
        it = S.upper_bound(A[i].b);
        if(it == S.end()) continue;
        tmp[++ cnt] = A[i]; S.erase(it);    
    }
    //cerr << cnt << endl;
    for(int i = 1; i <= cnt; ++ i)
        if(tmp[i].val + a[n - i + 1] > 0)
            ans += tmp[i].val + a[n - i + 1];
    cout << ans << endl;
    return 0;
}

T3

这个构造题其实还是不难的,只是考试的时候自己没有耐心去想.
并且数据范围还提示了 m = 2 k 时要特判

首先如果 m = 2 k
我们可以很容易构造出某一项为 0
首先 a = b = c = 1 ( 1 , 1 , 2 ) 即可
然后 a > 1 时,构造出 0 + 1 = 1 , 即选择 ( m 2 , 1 , 1 )
b > 1 同理
c > 1 时可以构造出 0 + 0 = 0 , 即选择 ( m 2 , m 2 , m 2 )

m 2 k
我们令 x = 2 k b , y = 2 k a , z = 2 l
那么可以得到一个方程 2 k a b + 1 = 2 c l ( m o d   m )
转换一下就是 k a b + 1 = c l
e x _ g c d 求解即可

时间复杂度 O ( T l o g m )

#include<bits/stdc++.h>

#define int long long

using namespace std;

int read() {
    int _ = 0, ___ = 1; char __ = getchar();
    for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
    for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return _ * ___;
}

void exgcd(int a, int b, int &x, int &y) {
    if(!b) {
        x = 1, y = 0; return;
    }
    exgcd(b, a % b, x, y); 
    int xx = y, yy = x - a / b * y;
    x = xx, y = yy;;
}

int T, m, a, b, c;

int qpow(int a, int x) {
    int ret = 1;
    while(x) {
        if(x & 1) (ret *= a) %= m;
        x >>= 1, (a *= a) %= m;
    }
    return ret;
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("1479.in", "r", stdin);
    freopen("1479.out", "w", stdout);
#endif
    for(T = read(); T -- ; ) {
        m = read(), a = read(), b = read(), c = read();
        int k = log2(m);
        if((1ll << k) == m) {
            if(a == 1 && b == 1 && c == 1) printf("1 1 2\n");
            else if(a > 1) printf("%lld 1 1\n", m / 2);
            else if(b > 1) printf("1 %lld 1\n", m / 2);
            else if(c > 1) printf("%lld %lld %lld\n", m / 2, m / 2, m / 2);
        }
        else {
            int x, y; exgcd(c, -a * b, x, y);
            while(x < 0 || y < 0) x += a * b, y += c;
            printf("%lld %lld %lld\n", qpow(2, y * b), qpow(2, y * a), qpow(2, x));
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81874699