Maratona de Programing da SBC 2019 11/13

A

bfs

#include <iostream>
#include <cstdint>
#include <queue>
#include <vector>
 
class Graph {
    int n;
    std::vector<std::vector<int>> es;
 
public:
    Graph (int n_): n(n_), es(n) {}
 
    void adde (int a, int b) {
        es[a].push_back(b);
    }
 
    bool bfs (int ibeg, int iend) {
        auto vis = std::vector<char>(n, 0);
        auto q = std::queue<int>();
        q.push(ibeg);
        vis[ibeg] = true;
 
        while (!q.empty()) {
            int c = q.front();
            q.pop();
 
            for (int nxt: es[c])
                if (!vis[nxt]) {
                    vis[nxt] = true;
                    q.push(nxt);
                }
        }
 
        return vis[iend];
    }
};
 
struct Sensor {
    int x, y, s;
 
    bool conn (Sensor const &rhs) const {
        int dx = x - rhs.x;
        int dy = y - rhs.y;
        int ss = s + rhs.s;
        return dx * dx + dy * dy <= ss * ss;
    }
};
 
int main () {
    std::ios::sync_with_stdio(false);
 
    int n, m, k;
    std::cin >> n >> m >> k;
 
    auto v = std::vector<Sensor>(k);
    for (auto &c: v)
        std::cin >> c.x >> c.y >> c.s;
 
    bool orz = false;
    auto g = Graph(n + 2);
    for (int i = 0; i < k; ++i)
        for (int j = 0; j < i; ++j)
            if (v[i].conn(v[j])) {
                g.adde(i, j);
                g.adde(j, i);
            }
 
    for (int i = 0; i < k; ++i) {
        auto &c = v[i];
        if (c.x <= c.s || c.y >= m - c.s)
            g.adde(n, i);
        if (c.x >= n - c.s || c.y <= c.s)
            g.adde(i, n + 1);
        if (c.conn(Sensor { 0, 0, 0 }) || c.conn(Sensor { n, m, 0 })) {
            orz = true;
            break;
        }
    }
 
    if (!orz)
        orz = g.bfs(n, n + 1);
 
    std::cout << (orz ? "N\n" : "S\n");
 
    return 0;
}

B

#include <iostream>
#include <vector>
 
int main () {
    int n;
    std::cin >> n;
    int x;
    std::cin >> x;
    bool orz = false;
    for (int i = 1; i < n; ++i) {
        int t;
        std::cin >> t;
        if (t > x)
            orz = true;
    }
    std::cout << (orz ? "N\n" : "S\n");
    return 0;
}

C

D

长链剖分,这个题的带修版本在comet oj上有,叫做黄金啥的。。。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <vector>
 
using namespace std;
 
int const N = 100005;
 
int dep[N];
vector<int> G[N];
int n, m;
int fa[N];
int son[N];
int len[N];
 
void dfs(int x) {
    for (auto y : G[x]) {
        dep[y] = dep[x] + 1;
        dfs(y);
        if (len[y] > len[x]) {
            len[x] = len[y];
            son[x] = y;
        }
    }
    len[x]++;
}
 
vector<int> ans;
void dfs2(int x, int t) {
    if (G[x].size() == 0u) {
        ans.push_back(dep[x] - dep[t] + 1);
        return;
    }
    if (son[x])
        dfs2(son[x], t);
    for (auto y : G[x]) {
        if (y == son[x])
            continue;
        dfs2(y, y);
    }
}
 
int main() {
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for (int i = 2; i <= n; ++i) {
        cin >> fa[i];
        G[fa[i]].push_back(i);
    }
    dfs(1);
    dfs2(1, 1);
    sort(ans.begin(), ans.end());
    reverse(ans.begin(), ans.end());
    int sum = 0;
    for (int i = 0; i < min(m, (int)ans.size()); ++i)
        sum += ans[i];
    cout << sum << '\n';
}

E

非常的有趣。
表示不会做然后看了别人的代码。
容易发现,对于一个鱼缸,显然你要么把公的全部拿出去,变回母的再拿回来(当然如果是变成母的就完成了那就不用拿回来了),或者是把所有母的都拿出去,留下公的变一条拿走一条。
因为容器的问题,所以不能是所有的鱼缸都是同一种拿出去的方式。
然后呢,因为变成母的之后完成了就不用拿回来,所以这里的天数还和空的有多少个有关。
但是注意到空鱼缸是可以能放就放的,而且是哪个鱼缸放过去并不影响。
所以你就 f [ i ] [ j ] [ k ] [ l ] f[i][j][k][l] f[i][j][k][l]表示到了第 i i i个鱼缸,现在有 j j j个空鱼缸还未放鱼,其中 k , l k,l k,l分别表示两种操作是否被使用。
注意到 j j j在中途可能为负数,故需要开到 2 N 2N 2N,但是这样就MLE了,再滚动一下就行。
所以这里具体到这个代码来说, j j j的意义实际上是,如果 j > = n j>=n j>=n,表示有 j − n j-n jn个空鱼缸可以使用,如果 j < n j<n j<n,表示已经已经有 n − j n-j nj条鱼可以使用/已经使用了空鱼缸,所以最后的答案应该在 0 < = j < = n 0<=j<=n 0<=j<=n中取

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

template<typename T, typename U>
inline void Remin(T& a, U const& b) {
	a = b < a ? b : a;
}

int const N = 3005;

int f[2][N << 1][2][2];
int n;
int mel[N], fem[N];

int main() {
	ios::sync_with_stdio(0);
	cin >> n;
	for (int i = 1; i <= n; ++i)
		cin >> mel[i] >> fem[i];
	
	bool is_all_empty = 1;
	for (int i = 1; i <= n; ++i)
		is_all_empty &= mel[i] == 0;
	if (is_all_empty) {
		cout << 0 << '\n';
		return 0;
	}
	memset(f, 127 / 2, sizeof(f));
	int INF = f[0][n][0][0];
	f[0][n][0][0] = 0;
	int now = 1;
	for (int i = 1; i <= n; ++i, now ^= 1)
		for (int j = 0; j <= n * 2; ++j)
			for (int k1 = 0; k1 < 2; ++k1)
				for (int k2 = 0; k2 < 2; ++k2) {
					if (f[now ^ 1][j][k1][k2] == INF)
						continue;
					Remin(f[now][max(0, j - mel[i])][1][k2], f[now ^ 1][j][k1][k2] + mel[i] * 2);
					Remin(f[now][j + (mel[i] == 0 && fem[i] == 0)][k1][1], f[now ^ 1][j][k1][k2] + mel[i] + fem[i] - 1);
					f[now ^ 1][j][k1][k2] = INF;
				}
	int ans = INF;
	for (int i = 0; i <= n; ++i)
		ans = min(ans, f[now ^ 1][i][1][1]);
	cout << ans << '\n';
}

F

G

费用流板子,只不过费用是小数而已

#include <cstdio>
#include <limits>
#include <algorithm>
#include <cmath>
#include <utility>
#include <fstream>
#include <limits>
#include <queue>
#include <iostream>
#include <cstdint>
#include <vector>
 
const double INF = 1e300;
const double EPS = 1e-10;
 
class Graph {
public:
    struct E {
        int to;
        int f;
        double w;
    };
 
    int n;
    std::vector<E> es;
    std::vector<std::vector<int>> nxt;
    std::vector<std::pair<double, int>> dis;
    std::vector<char> inq;
 
    Graph (int n): n(n), es(), nxt(n), dis(n), inq(n) {}
 
    void adde (int a, int b, int f, double w) {
        // std::cerr << "+ " << a << "->" << b << " f=" << f << " w=" << w << "\n";
        int idx = es.size();
        es.push_back(E { b, f, w });
        es.push_back(E { a, 0, -w });
        nxt[a].push_back(idx);
        nxt[b].push_back(idx + 1);
    }
 
    void spfa (int ibeg) {
        for (int i = 0; i < n; ++i)
            dis[i] = { INF, -1 };
        for (int i = 0; i < n; ++i)
            inq[i] = 0;
 
        std::queue<int> q;
        q.push(ibeg);
        dis[ibeg] = { 0.0, -1 };
 
        while (!q.empty()) {
            int c = q.front();
            q.pop();
            inq[c] = false;
 
            for (int idx: nxt[c]) {
                auto &e = es[idx];
                if (e.f && dis[e.to].first > dis[c].first + e.w + EPS) {
                    dis[e.to] = { dis[c].first + e.w, idx };
                    // std::cerr << "ext " << c << "->" << e.to << " =" << dis[e.to].first << "\n";
                    if (!inq[e.to]) {
                        inq[e.to] = true;
                        q.push(e.to);
                    }
                }
            }
        }
    }
 
    void cost_flow (int ibeg, int iend) {
        while (spfa(ibeg), dis[iend].second != -1) {
            // std::cerr << dis[iend].first << '\n';
 
            int f = std::numeric_limits<int>::max();
            for (int i = iend; dis[i].second != -1; ) {
                int idx = dis[i].second;
                f = std::min(f, es[idx].f);
                i = es[idx ^ 1].to;
            }
 
            for (int i = iend; dis[i].second != -1; ) {
                int idx = dis[i].second;
                es[idx].f -= f;
                es[idx ^ 1].f += f;
                i = es[idx ^ 1].to;
            }
        }
    }
};
 
 
int main () {
    std::ios::sync_with_stdio(false);
 
    int n;
    std::cin >> n;
 
    auto g = Graph(n + n + 2);
    int ibeg = n + n, iend = ibeg + 1;
    for (int i = 0; i < n; ++i) {
        g.adde(ibeg, i, 1, 0);
        g.adde(n + i, iend, 1, 0);
    }
 
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j) {
            int x;
            std::cin >> x;
            double w = log((double)x);
            g.adde(i, n + j, 1, -w);
        }
 
    g.cost_flow(ibeg, iend);
 
    auto ans = std::vector<int>(n);
    for (int i = 0; i < n; ++i)
        for (int idx: g.nxt[i])
            if (g.es[idx].f == 0) {
                // ans[i] = g.es[idx].to - n;
                ans[g.es[idx].to - n] = i;
                break;
            }
 
    for (int x: ans)
        std::cout << x + 1 << ' ';
    std::cout << '\n';
 
    return 0;
}

H

#include <iostream>
#include <cstdio>
 
using namespace std;
 
int main() {
    int n, m;
    cin >> n >> m;
    long long s = n * m;
    for (int i = 1; i <= 9; ++i) {
        cout << (s * i + 9) / 10;
        if (i == 9)
            cout << '\n';
        else
            cout << ' ';
    }
}

I

显然考虑floyed,但是这里是要求不包括起点和终点的路径上的点权要第K大/小
那么就按温度依次把点拿来当中间点来更新所有点就行。
这里的题意有点emmmmmm
补题的时候看了clar才发现真相x

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <utility>

using namespace std;

#define SZ(x) ((int)(x).size())

using pii = pair<int, int>;

int const N = 405;
int const M = 100005;
int const INF = 1e9;

int g[N][N];
int n, m;
int ans[M];

struct ques {
	int x, y;
	int K;
	int id;
	bool operator < (ques const& oth) const {
		return K < oth.K;
	}
};
vector<ques> que[2];
int qn;
int T[N];
int id[N];

void solve(vector<ques>& q) {
	sort(q.begin(), q.end());
	int p = 0;
	static int f[N][N];
	memcpy(f, g, sizeof(f));
	int tp = 0;
	for (int i = 1; i <= n; ++i) {
		int now = id[i];
		for (int j = 1; j <= n; ++j) 
			for (int k = 1; k <= n; ++k)
				f[j][k] = min(f[j][k], f[j][now] + f[now][k]);
		if (i == n || T[id[i]] != T[id[i + 1]]) {
			++tp;
			while (p < SZ(q) && (q[p].K == tp || i == n)) {
				ans[q[p].id] = f[q[p].x][q[p].y];
				++p;
			}
		}
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		cin >> T[i];
		id[i] = i;
	}
	sort(id + 1, id + n + 1, [=] (int const& x, int const& y) {
			return T[x] < T[y];
	});
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			g[i][j] = INF;
	for (int i = 1; i <= m; ++i) {
		int x, y, w;
		cin >> x >> y >> w;
		g[x][y] = g[y][x] = w;
	}
	cin >> qn;
	for (int i = 0; i < qn; ++i) {
		int x, y, K, op;
		cin >> x >> y >> K >> op;
		que[op].push_back({ x, y, K, i });
	}
	solve(que[0]);
	reverse(id + 1, id + n + 1);
	solve(que[1]);
	for (int i = 0; i < qn; ++i)
		cout << (ans[i] >= INF ? -1 : ans[i]) << '\n';
}

J

模拟一下下。

#include <iostream>
#include <vector>
#include <array>
 
char stupid_ord[] = "A23456789DQJK";
const int N = sizeof stupid_ord - 1 + 2;
int ord[256];
 
int main () {
    std::ios::sync_with_stdio(false);
 
    for (int i = 0; stupid_ord[i]; ++i)
        ord[(int)stupid_ord[i]] = i;
 
    using Arr = std::array<char, N>;
 
    int n, k;
    std::cin >> n >> k;
    auto v = std::vector<Arr>(n);
    for (int i = 0; i < n; ++i) {
        char s[5];
        std::cin >> s;
        for (int j = 0; j < 4; ++j) {
            // std::cerr << "+card " << ord[(int)s[j]] << '\n';
            ++v[i][ord[(int)s[j]]];
        }
    }
 
    auto is_win = [&](Arr const &arr) {
        for (int i = 0; i < N - 2; ++i)
            if (arr[i] == 4)
                return true;
        return false;
    };
 
    int cur = k - 1, win;
 
    for (int i = 0; i < n; ++i)
        if (i != cur && is_win(v[i])) {
            std::cout << i + 1 << '\n';
            return 0;
        }
 
    ++v[cur][N - 1];
    // int cnt = 0;
    for (;;) {
        // std::cerr << "cur=" << cur << '\n';
        // for (int i = 0; i < N - 2; ++i)
        //     std::cerr << (int)v[cur][i] << ' ';
        // std::cerr << '\n';
 
        // if (++cnt == 5)
        //     return 1;
        int nxt = (cur + 1) % n;
        // int nxt = (cur - 1 + n) % n;
        if (v[cur][N - 2]) {
            // std::cerr << cur << "->" << nxt << " X\n";
            --v[cur][N - 2];
            ++v[nxt][N - 1];
        } else {
            int imx = -1;
            for (int i = 0; i < N - 2; ++i)
                if (v[cur][i] && (imx == -1 || v[cur][i] < v[cur][imx]))
                    imx = i;
            --v[cur][imx];
            ++v[nxt][imx];
            // std::cerr << cur << "->" << nxt << " " << imx << "\n";
 
            if (v[cur][N - 1]) {
                // std::cerr << cur << " down\n";
                --v[cur][N - 1];
                ++v[cur][N - 2];
            }
        }
 
        if (is_win(v[cur])) {
            win = cur;
            break;
        }
 
        cur = nxt;
    }
 
    std::cout << win + 1 << '\n';
 
    return 0;
}

K

苦推若干小时,最后大力上BM居然找出来了解。。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<vector>
#include<cassert>
using namespace std;
 
typedef vector<int> VI;
typedef long long LL;
typedef pair<int,int> PII;
 
const LL MOD = 1000000007;
 
LL KSM(LL a,LL k) {
	LL ret=1; a%=MOD;
	assert(k>=0);
	while(k) {
		if(k&1) ret=ret*a%MOD;
		a=a*a%MOD;
		k>>=1;
	}
	return ret;
}
 
int _;
LL n;
namespace linear_seq {
	const int N = 10010;
	LL res[N],base[N],_c[N],_md[N];
 
	vector<LL> Md;
	void mul(LL *a,LL *b, LL k) {
		for(int i=0;i<k+k;i++) _c[i]=0;
		for(int i=0;i<k;i++) if(a[i]) {
			for(int j=0;j<k;j++) {
				_c[i+j]=(_c[i+j]+a[i]*b[j])%MOD;
			}
		}
		for(int i=k+k-1;i>=k;i--) if(_c[i])
		  for(int j=0;j<Md.size();j++) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%MOD;
		for(int i=0;i<k;i++) a[i]=_c[i];
	}
	int solve(LL n,VI a,VI b) {
		LL ans=0,pnt=0;
		LL k=a.size();
		assert(a.size()==b.size());
		for(int i=0;i<k;i++) _md[k-1-i]=-a[i];
		_md[k]=1;
		Md.clear();
		for(int i=0;i<k;i++) if(_md[i]!=0) Md.push_back(i);
		for(int i=0;i<k;i++) res[i]=base[i]=0;
		res[0]=1;
		while((1ll<<pnt)<=n) pnt++;
		for(LL p=pnt;p>=0;p--) {
			mul(res,res,k);
			if((n>>p)&1) {
				for(int i=k-1;i>=0;i--) res[i+1]=res[i];
				res[0]=0;
				for(int j=0;j<Md.size();j++) {
					res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%MOD;
				}
			}
		}
		for(int i=0;i<k;i++) ans=(ans+res[i]*b[i])%MOD;
		if(ans<0) ans+=MOD;
		return ans;
	}
	VI BM(VI s) {
		VI C(1,1),B(1,1);
		LL L=0,m=1,b=1;
		for(int n=0;n<s.size();n++) {
			LL d=0;
			for(int i=0;i<=L;i++) d=(d+(LL)C[i]*s[n-i])%MOD;
			if(d==0) m++;
			else if(2*L<=n) {
				VI T=C;
				LL c=MOD-d*KSM(b,MOD-2)%MOD;
				while(C.size()<B.size()+m) C.push_back(0);
				for(int i=0;i<B.size();i++) {
					C[i+m]=(C[i+m]+c*B[i])%MOD;
				}
				L=n+1-L;
				B=T;
				b=d;
				m=1;
			} else {
				LL c=MOD-d*KSM(b,MOD-2)%MOD;
				while(C.size()<B.size()+m) C.push_back(0);
				for(int i=0;i<B.size();i++) {
					C[i+m]=(C[i+m]+c*B[i])%MOD;
				}
				m++;
			}
		}
		return C;
	}
    int gao(VI a,LL n) {
        //VI c=BM(a);
        //c.erase(c.begin());
        //for(int i=0;i<((int)c.size());i++) c[i]=(MOD-c[i])%MOD;
		VI c = { 6, -8 + MOD, -8 + MOD, 16 };
		//reverse(c.begin(), c.end());
        return solve(n,c,VI(a.begin(),a.begin()+((int)c.size())));
    }
};
 
static bool vis[10][3];
void dfs(int x, int y, int& ans, int sum) {
	if (!(1 <= x && x <= n && 1 <= y && y <= 2))
		return;
	if (vis[x][y])
		return;
	vis[x][y] = 1;
	sum++;
	if (sum == n * 2) {
		++ans;
		vis[x][y] = 0;
		return;
	}
	for (int i = -1; i <= 1; ++i)
		for (int j = -1; j <= 1; ++j)
			if (i != 0 || j != 0) {
				dfs(x + i, y + j, ans, sum);
			}
	vis[x][y] = 0;
}
 
/*
2 :: 24
3 :: 96
4 :: 416
5 :: 1536
6 :: 5504
7 :: 18944
8 :: 64000
9 :: 212992
10 :: 702464
 */
 
int main() {
	/*
	for (n = 2; n <= 10; ++n) {
		int ans = 0;
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= 2; ++j) {
				memset(vis, 0, sizeof(vis));
				dfs(i, j, ans, 0);
			}
		cout << ans << '\n';
	}
	return 0;
	*/
	scanf("%lld",&n);
    if (n == 1)
        puts("2");
    else
        printf("%d\n",linear_seq::gao(VI{24, 96, 416, 1536, 5504, 18944, 64000, 212992}, n - 2));
    return 0;
}

L

可以推出式子是
∑ i = 0 n C ( n , i ) % 2 \sum_{i = 0}^n C(n, i) \% 2 i=0nC(n,i)%2
然后lucas一下,就发现了其实就是2的xxx次方

#include <iostream>
 
using namespace std;
 
using ll = long long;
 
int main() {
    ll n;
    cin >> n;
    cout << (1ll << (__builtin_popcountll(n))) << '\n';
    return 0;
}

M

二分答案

#include <iostream>
#include <cstdio>
#include <cmath>
 
using namespace std;
 
using ll = long long;
 
int const N = 1e5 + 5;
 
int a[N];
int n, m, K;
 
bool check(ll lim) {
    ll s = 0;
    int can = 0;
    for (int i = 1; i <= n; ++i) {
        if (a[i] > lim * K)
            return 0;
        if (s + a[i] > lim * K) {
            ++can;
            s = a[i];
        } else
            s += a[i];
    }
    if (s)
        ++can;
    return can <= m;
}
 
int main() {
    cin >> n >> m >> K;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    int l = 1, r = 1e9, ans = -1;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid)) {
            ans = mid;
            r = mid - 1;
        } else
            l = mid + 1;
    }
    cout << ans << '\n';
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值