zoukankan      html  css  js  c++  java
  • 9.25李赛 挂成狗了 & 被打爆了

    挂成狗了。

    A LOJ #6720. 「CodePlus #7」最小路径串

    对于每一个点的出边按照到达点的编号大小排序。

    dfs 一下。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define pb emplace_back
    typedef long long ll;
    typedef std::vector<int> veci;
    const ll mod = 998244353;
    const int N = 1000010;
    int n, m, ent, head[N];
    ll dis[N];
    bool vis[N];
    char ch[N*12];
    veci eg[N];
    int to_int(int l, int r) {
    	int w = 0;
    	for(int i = l; i <= r; ++i) w = w * 10 + (ch[i] - '0');
    	return w;
    }
    void dfs(int x, int f) {
    	vis[x] = 1; dis[x] = (dis[f] * 1000000 % mod + x) % mod;
    	std::sort(eg[x].begin(), eg[x].end());
    	for(auto v : eg[x]) if(!vis[v]) dfs(v, x);
    }
    signed main() {
    	scanf("%d%d", &n, &m);
    	scanf("%s", ch+1);
    	for(int i = 1; i <= 12 * m; i += 12) {
    		int x = to_int(i, i+5), y = to_int(i+6, i+11);
    		eg[x].pb(y); eg[y].pb(x);
    	}
    	dfs(0, 0);
    	for(int i = 1; i < n; ++i) printf("%lld
    ", !vis[i] ? -1ll : dis[i]);
    	return 0;
    }
    

    B LOJ #2743. 「JOI Open 2016」摩天大楼

    麻了,这题为什么在第二题,卡常卡吐了。还忘了判 n=1

    排下序,易得 dp:(f_{i,j,k,0/1,0/1}) 表示考虑前 (i) 个数,有 (j) 个连续段,费用为 (k),左/右的顶端有没有填掉。

    这样 (k) 的枚举范围大概是个 (2sum a),但实际上可以再紧一紧,然后滚动数组,用 vector 卡卡空间,就这样 (mathcal{O}(n^3a)) 在LOJ上卡过去了...

    优化到 (mathcal{O}(n^2L)) 的话,考虑费用提前计算,这样的话向后转移 (k) 是不降的,(k) 的枚举范围就到 (L) 就可以了。

    代码是 (mathcal{O}(n^3a)) 的做法。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define pb emplace_back
    typedef long long ll;
    const ll mod = 1000000007;
    ll Add(ll x, ll y) { return (x + y >= mod) ? (x + y - mod) : (x + y); }
    ll Mul(ll x, ll y) { return x * y % mod; }
    ll Mod(ll x) { return (x >= mod) ? (x - mod) : (x < 0 ? (x + mod) : x); }
    inline ll cadd(int &x, ll y) { return x = (x + y >= mod) ? (x + y - mod) : (x + y); }
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 101;
    const int L = 1001;
    int n, l, a[N], sum, all, lim;
    int len[N][2][2];
    std::vector<int> f[N][2][2], g[N][2][2];
    int cmp(int x, int y) { return x > y; }
    signed main() {
    	read(n); read(l);
    	if(n == 1) {
    		puts("1");
    		return 0;
    	}
    	for(int i = 1; i <= n; ++i) read(a[i]), all += a[i];
    	std::sort(a + 1, a + n + 1, cmp);
    	for(int i = 0; i <= n; ++i)
    		for(int p1 = 0; p1 <= 1; ++p1)
    			for(int p2 = 0; p2 <= 1; ++p2)
    				f[i][p1][p2].pb(0), f[i][p1][p2].pb(0),
    				g[i][p1][p2].pb(0), g[i][p1][p2].pb(0);
    	f[0][0][0][0] = 1;
    	for(int o = 1; o <= n; ++o) {
    		sum += a[o]; lim = Min(sum, l + 2 * (all - sum) + 2*a[o]);
    		for(int i = 0; i <= o; ++i)
    			for(int p1 = 0; p1 <= 1; ++p1)
    				for(int p2 = 0; p2 <= 1; ++p2)
    					while(len[i][p1][p2] <= 2*lim)
    						f[i][p1][p2].pb(0), g[i][p1][p2].pb(0), ++len[i][p1][p2];
    		for(int i = 0; i < o; ++i)
    			for(int j = 0; j <= 2*(lim-a[o]); ++j) 
    				for(int p1 = 0; p1 <= 1; ++p1)
    					for(int p2 = 0; p2 <= 1; ++p2) {
    						if(!f[i][p1][p2][j]) continue ;
    						cadd(g[i+1][p1][p2][j+2*a[o]], 1ll * f[i][p1][p2][j] * (i+1-p1-p2) % mod); //新开一个连通块 且不在左/右 
    						if(!p1) cadd(g[i+1][1][p2][j+a[o]], 1ll * f[i][p1][p2][j]); //新开一个连通块 在左
    						if(!p2) cadd(g[i+1][p1][1][j+a[o]], 1ll * f[i][p1][p2][j]); //新开一个连通块 在右
    						if(i) cadd(g[i][p1][p2][j], 1ll * f[i][p1][p2][j] * (2*i-p1-p2) % mod); //连上之前一个连通块 且不在左/右
    						if(!p1 && i) cadd(g[i][1][p2][j-a[o]], 1ll * f[i][p1][p2][j]); //连上之前一个连通块 在左
    						if(!p2 && i) cadd(g[i][p1][1][j-a[o]], 1ll * f[i][p1][p2][j]); //连上之前一个连通块 在右
    						if(i>=2) cadd(g[i-1][p1][p2][j-2*a[o]], 1ll * f[i][p1][p2][j] * (i-1) % mod);//连接两个联通块
    					}
    		for(int i = 0; i <= o; ++i)
    			for(int j = 0; j <= 2*lim; ++j)
    				for(int p1 = 0; p1 <= 1; ++p1)
    					for(int p2 = 0; p2 <= 1; ++p2)
    						f[i][p1][p2][j] = g[i][p1][p2][j],
    						g[i][p1][p2][j] = 0;
    	}
    	int ans = 0;
    	while(len[1][1][1] <= l) f[1][1][1].pb(0), ++len[1][1][1];
    	for(int i = 0; i <= Min(l, len[1][1][1]); ++i) {
    		cadd(ans, 1ll*f[1][1][1][i]);
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

    C LOJ #6723. 「CodePlus #7」教科书般的亵渎 / Luogu P5068 [Ynoi2015] 我回来了

    麻了,本来是能切掉这个简单的Ynoi题的,但是看错 (0) 的个数,数组开小了...咋还能这样挂分的...

    每个伤害值 (d) 可以分开考虑,那就考虑它在哪个时刻,对答案的贡献加了个 (1),这些总和是个调和级数 (mathcal{O}(nlog n)) 的。

    离线下来,对于每个值记录它最早在哪个时刻加入,用个线段树 / ST表查询区间最小值,对于每一个 (d) 暴力枚举 ([1,d],[d+1,2d]...),然后看区间最小值,再做个前缀 (max),就知道具体是在哪个时刻答案 (+1) 了。

    最后统计答案的时候用个树状数组,支持单点 (+1),查询区间和就可以了,修改次数是 (mathcal{O}(nlog n)),查询是 (mathcal{O}(m)) 的。

    总复杂度是 (mathcal{O}(nlog^2n+mlog n)) 的。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #define pb push_back
    typedef long long ll;
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    inline int lowbit(int x) { return x & (-x); }
    const int N = 1000010;
    const int INF = 0x7fffffff;
    int n, m;
    int b[N];
    std::vector<int>vec[N]; 
    namespace Segment_Tree {
    	#define ls tree[x].lson
    	#define rs tree[x].rson
    	#define tl tree[x].l
    	#define tr tree[x].r
    	int trnt;
    	struct SGT {
    		int l, r, mn, lson, rson;
    	}tree[N << 1];
    	inline void pushup(int x) { tree[x].mn = Min(tree[ls].mn, tree[rs].mn); }
    	int build(int l, int r) {
    		int x = ++trnt; tl = l; tr = r;
    		if(l == r) {
    			tree[x].mn = b[l];
    			return x;
    		}
    		int mid = (l + r) >> 1;
    		ls = build(l, mid); rs = build(mid+1, r);
    		pushup(x);
    		return x;
    	}
    	int query(int x, int l, int r) {
    		if(tl >= l && tr <= r) return tree[x].mn;
    		int mid = (tl + tr) >> 1, sumq = INF;
    		if(mid >= l) sumq = Min(sumq, query(ls, l, r));
    		if(mid < r) sumq = Min(sumq, query(rs, l, r));
    		return sumq;
    	}
    	#undef ls
    	#undef rs
    	#undef tl
    	#undef tr
    }
    using namespace Segment_Tree;
    int opt[N], l[N], r[N], h[N], t[N];
    int tr[N];
    void modify(int x, int v) { for(; x <= n; x += lowbit(x)) tr[x] += v; }
    int query(int x) { int sumq = 0; for(; x; x -= lowbit(x)) sumq += tr[x]; return sumq; }
    int qsum(int l, int r) { return query(r) - query(l-1); }
    signed main() {
    	read(n); read(m);
    	for(int i = 1; i <= n; ++i) b[i] = INF;
    	for(int i = 1; i <= m; ++i) {
    		read(opt[i]);
    		if(opt[i] == 1) read(h[i]), b[h[i]] = Min(b[h[i]], i);
    		else read(l[i]), read(r[i]);
    	}
    	build(1, n);
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; (j-1)*i < n; ++j) {
    			t[j] = query(1, (j-1)*i+1, Min(j*i, n));
    			if(t[j] == INF) break ;
    		}
    		for(int j = 1; (j-1)*i < n; ++j) {
    			if(t[j] == INF) break ;
    			t[j] = Max(t[j], t[j-1]);
    			vec[t[j]].pb(i);
    		}
    	}
    	for(int i = 1; i <= m; ++i) {
    		for(auto x : vec[i]) modify(x, 1);
    		if(opt[i] == 2) {
    			printf("%d
    ", r[i]-l[i]+1 + qsum(l[i], r[i]));
    		}
    	}
    	return 0;
    }
    

    D LOJ #2350. 「JOI 2018 Final」月票购买

    不会做,被打爆了...

    考虑找出在 (S o T) 最短路上的边,形成个 DAG(正反方向都可以),两种方向分别考虑。

    结论是 (U o V) 的路径如果和 (S o T) 的最短路相交,则仅有一段相交,因为如果有两段的话,显然中间断开的路走 (S o T) 的最短路更优。

    那就在 DAG 上拓扑排序 / dfs,对于每个点记录能走到它的点(或者它能走到的点)的 (dis(U,y),dis(V,y)) 的最小值,分别记作 (f_x,g_x),答案即为 (min{f_x+dis(V,x),g_x+dis(U,x),dis(U,V)})

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define mp std::make_pair
    #define fir first
    #define sec second
    typedef long long ll;
    typedef std::pair<ll, int> pli;
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 100010;
    const ll INF = 0x7fffffffffffffff;
    int n, m, S, T, U, V;
    int ent = 1, head[N], pre[N];
    ll dS[N], dT[N], dU[N], dV[N], f[N], g[N], ans;
    bool vis[N];
    struct Egde {
    	int to, val, nxt;
    }e[N<<2];
    inline void add(int x, int y, int z) {
    	e[++ent].to = y; e[ent].val = z; e[ent].nxt = head[x]; head[x] = ent;
    }
    void Dij(int s, ll *dis) {
    	for(int i = 1; i <= n; ++i) vis[i] = 0, dis[i] = INF;
    	dis[s] = 0;
    	std::priority_queue<pli>q;
    	q.push(mp(0, s));
    	while(!q.empty()) {
    		int x = q.top().sec; q.pop();
    		if(vis[x]) continue ;
    		vis[x] = 1;
    		for(int i = head[x]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if(dis[v] > dis[x] + e[i].val) {
    				dis[v] = dis[x] + e[i].val;
    				q.push(mp(-dis[v], v));
    			}
    		}
    	}
    }
    void dfs(int x) {
    	if(vis[x]) return ;
    	vis[x] = 1; f[x] = dU[x]; g[x] = dV[x];
    	for(int i = head[x]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if(dS[x] + dT[v] + e[i].val != dS[T]) continue ;
    		dfs(v);
    		f[x] = Min(f[x], f[v]); g[x] = Min(g[x], g[v]);
    	}
    	ans = Min(ans, Min(f[x] + dV[x], g[x] + dU[x]));
    }
    signed main() {
    	read(n); read(m);
    	read(S); read(T);
    	read(U); read(V);
    	for(int i = 1; i <= m; ++i) {
    		int u, v, w; read(u); read(v); read(w);
    		add(u, v, w);
    		add(v, u, w);
    	}
    	Dij(S, dS); Dij(T, dT); Dij(U, dU); Dij(V, dV); ans = INF;
    	for(int i = 1; i <= n; ++i) f[i] = g[i] = 0x3f3f3f3f3f3f3f3f, vis[i] = 0;
    	dfs(S);
    	ans = Min(ans, dU[V]);
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    hdu 5007 水题 (2014西安网赛A题)
    hdu 1698 线段树(成段替换 区间求和)
    poj 3468 线段树 成段增减 区间求和
    hdu 2795 公告板 (单点最值)
    UVaLive 6833 Miscalculation (表达式计算)
    UVaLive 6832 Bit String Reordering (模拟)
    CodeForces 124C Prime Permutation (数论+贪心)
    SPOJ BALNUM (数位DP)
    CodeForces 628D Magic Numbers (数位DP)
    POJ 3252 Round Numbers (数位DP)
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15334435.html
Copyright © 2011-2022 走看看