[ 算法竞赛进阶指南 0x00 ] 杂谈

版权声明:https://blog.csdn.net/qq_40831340 欢迎斧正 https://blog.csdn.net/qq_40831340/article/details/90638849

持续更新。。。。

汉诺塔

首先考虑n个盘子3塔的经典Hanoi问题,设dn表示求解n个盘子3塔问题的最少步数,显然有
dn=2∗dn−1+1

含义为把前n−1个盘子从A借助C转移到B,再将第n个盘子转移到C,最后把n−1个盘子从B借助A转移到C。

类似地,对于本题,设f[n]表示求解n个盘子4塔问题的最小步数,则有
fn=min(2∗fi+dn−i)(1≤i<n)

含义为把前i个盘子在4柱的情况下从A转移到B,再将n−i个盘子在3柱的情况下从A转移到D,最后再将i个盘子在4柱的情况下从B转移到D
  
那么对于n盘m塔的问题(m>4),就有
fn,m=min(2∗fi,m+fn−i,m−1)(1≤i<n)

使得我们可以在O(n2∗m)的复杂度内求解该问题

#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
#define int long long
typedef long long ll;

const int maxn = 25 + 5 ;
const int INF = 0x3f3f3f3f;
int n, m, mod;

int dp[20];
int d[20];

signed main() {
    fastio;
    d[1] = 1;
    for(int i = 2; i <= 15; i++) {
        d[i] = d[i - 1] * 2 + 1;
    }

    memset(dp, 0x3f, sizeof(dp));
    dp[1] = 1;

    for(int i = 2; i <= 15; i++) {
        for(int j = 1; j < i; j++) {
            dp[i] = min(dp[i], d[i - j] + dp[j] * 2);
        } // 2 * 4塔模式  + 1 * 3塔模式
    }

    for(int i = 1; i <= 12; i++) {
        cout << dp[i] << endl;
    }
    return 0;
}

对顶堆

小堆(pop大的) 保持小堆刚好大于大根堆一个 这样小堆队首第一个就是中位数

#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
#define int long long
typedef long long ll;

const int maxn = 1e4 + 5 ;

int n, m, mod;
int a[maxn];
int que[maxn], tail, head;

signed main() {
    fastio;
    int t;
    cin >> t;
    for(int cas = 1; cas <= t; cas++) {
        priority_queue<int, vector<int>, greater<int> > xh;
        priority_queue<int, vector<int>, less<int> > dh;
        cin >> m;
        cin >> n;
        cout << m << " " << (n + 1) / 2 << endl;
        tail = 1;
        head = 1;

        for(int i = 1; i <= n; i++) {
            cin >> m;
            if(i == 1)
                xh.push(m);
            else if(xh.top() < m)
                xh.push(m);
            else
                dh.push(m);

            if(xh.size() < dh.size())
                xh.push(dh.top()), dh.pop();
            else if(xh.size() > dh.size()+1)
                dh.push(xh.top()), xh.pop();

            if(i & 1)
                que[tail++] = xh.top();
        }

        for(int i = head; i < tail; i++) {
            cout << que[i] << " ";
            if(i % 10 == 0)
                cout << endl;
        }
        cout << endl;
    }
    return 0;
}

#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
#define int long long
typedef long long ll;

const int maxn = 1e4 + 5 ;

int n, m, mod;
int a[maxn];
int que[maxn], tail, head;

signed main() {
    fastio;
    int t;
    cin >> t;
    for(int cas = 1; cas <= t; cas++) {
        priority_queue<int, vector<int>, greater<int> > xh;
        priority_queue<int, vector<int>, less<int> > dh;
        cin >> m;
        cin >> n;
        cout << m << " " << (n + 1) / 2 << endl;
        tail = 1;
        head = 1;

        for(int i = 1; i <= n; i++) {
            cin >> m;
            if(i == 1)
                xh.push(m);
            else if(xh.top() < m)
                xh.push(m);
            else
                dh.push(m);

            if(xh.size() < dh.size())
                xh.push(dh.top()), dh.pop();
            else if(xh.size() > dh.size()+1)
                dh.push(xh.top()), xh.pop();

            if(i & 1)
                que[tail++] = xh.top();
        }

        for(int i = head; i < tail; i++) {
            cout << que[i] << " ";
            if(i % 10 == 0)
                cout << endl;
        }
        cout << endl;
    }
    return 0;
}

约数之和

分治 入门 极大的降低复杂度

#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 100000 + 5 ;
const int INF = 0x3f3f3f3f ;
const int mod = 9901 ;

int p[50], c[50];
int cnt;

void divide(int n) {
	cnt = 0;
	for(int i = 2; i <= sqrt(n); i++) {
		if(n % i == 0) {
			p[++cnt] = i, c[cnt] = 0;
			while(n % i == 0)
				n /= i, c[cnt]++;
		}
	}
	if(n > 1)
		p[++cnt] = n, c[cnt] = 1;
}

int power(int a, int b) {
	int res = 1 % mod;
	while(b) {
		if(b & 1)
			res = 1ll * res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

int sum(int pt, int ct) {
	if(ct == 0)
		return 1;
	if(ct % 2 == 1)
		return ((1 + power(pt, (ct + 1) >> 1)) * sum(pt, (ct - 1) >> 1)) % mod;
	else
		return ((1 + power(pt, ct >> 1)) * sum(pt, (ct >> 1) - 1) % mod + power(pt, ct)) % mod;
}

signed main() {
	fastio;
	int a, b;
	cin >> a >> b;
	if(a == 0) {
		cout << 0 << endl;
		return 0;
	}
	divide(a);
	int ans = 1;
	for(int i = 1; i <= cnt; i++) {
		ans = (ans * sum(p[i], c[i] * b)) % mod;
	}
	cout << ans << endl;
	return 0;
}

最佳牛围栏 二分左右边界问题

二分平均值
当平均值够的时候 我们的某个不小于L的字段和应该大于0
此时 对于每个值-=mid
不断二分
最后找刚好使字段和足够支持mid的l r 便是答案

#include <bits/stdc++.h>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 100000 + 5 ;
const int INF = 0x3f3f3f3f ;
const int mod = 9901 ;
const double eps = 1e-8;
int n, L;

double a[maxn], b[maxn];
double sum[maxn];

bool chk(double mid) {
    for(int i = 1; i <= n; i++)
        b[i] = a[i] - mid;
    for(int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + b[i];

    double min_val = 1e10, ans = -1e10;

    for(int i = L ; i <= n; i++) {
        min_val = min(min_val, sum[i-L]);
        ans = max(ans, sum[i] - min_val);
    }
    return ans >= 0;
}

signed main() {
    fastio;
    cin >> n >> L;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    double l = 0, r = 1e8;
    while(r-l>=eps) {
        double mid = (l + r) / 2;

        if(chk(mid))
            l = mid;
        else
            r = mid;
    }
    cout << (int)(r * 1000) << endl;
    return 0;
}

三分

链接 : [ 三分法 ] 单峰(单谷)函数 三分找极点

七夕祭

这题和货舱选址 用中位数 并且 和 均分纸牌有关

首先我们 先想 对一个列 or 行 进行纸牌均分 而且他是成环的 我们可以考虑从k人隔开
跑 P33 上 前缀和那个公式 但是我们发现 为了让这个和最小 我们最好 选中位数(货舱选址) 所以这题就这样狗出来了
ps N, M, 这东西打反也没有谁了 wa2法。。。

#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;

const int maxn = 100000 + 5;

int N, M, T;
int c[2][maxn], a[maxn], s[maxn];

signed main(){
    cin >> N >> M >> T;
    for(int i = 1; i <= T; i ++ ) {
        int x, y;
        cin >> x >> y;
        c[0][y] ++;
        c[1][x] ++;
    }
    if((T % N) != 0 && (T % M) != 0) {
        cout << "impossible" << endl;
        return 0;
    }
    int ans = 0, flag = 0, ok = 0;
    if((T % M) == 0){
        int TM = T / M;
        for(int i = 1; i <= M; i ++ ) {
            a[i] = c[0][i] - TM;
            s[i] = s[i - 1] + a[i];
        }
        sort(s + 1, s + 1 + M);
        int mid = s[M + 1 >> 1];
        for(int i = 1; i <= M; i ++ ) {
            ans += abs(s[i] - mid);
        }
        ok = 1;
    }
    if((T % N) == 0){
        int TM = T / N;
        for(int i = 1; i <= N; i ++ ) {
            a[i] = c[1][i] - TM;
            s[i] = s[i - 1] + a[i];
        }
        sort(s + 1, s + 1 + N);
        int mid = s[N + 1 >> 1];
        for(int i = 1; i <= N; i ++ ) {
            ans += abs(s[i] - mid);
        }
        flag = 1;
    }
    if(flag && ok) cout << "both " << ans << endl;
    else if(flag) cout << "row " << ans << endl;
    else cout << "column " << ans << endl;
    return 0;
}

倍增 未完 待续

猜你喜欢

转载自blog.csdn.net/qq_40831340/article/details/90638849