Codeforces Round #548 (Div. 2)

比赛链接
cf

A

最后一位判定

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#define P(x, y) 1ll * (x) * inv(y) % P
using namespace std;
typedef long long ll;
const int N = 65005;
const ll P = 1e9 + 7;
int n;
ll ans;
char str[N];
int main(){
	scanf("%d%s", &n, str + 1);
	for(int i = 1; i <= n; ++i){
		if(!((str[i] - '0') & 1)) ans += i;
	}
	printf("%lld", ans);
	return 0;
}

B

倒叙维护最大值

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#define P(x, y) 1ll * (x) * inv(y) % P
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
const ll P = 1e9 + 7;
int n, a[N], lim;
ll ans;
int main(){
	scanf("%d", &n);
	for(int i = 1, x; i <= n; ++i){
		scanf("%d", &a[i]);
	}
	lim = a[n]; ans += a[n];
	for(int i = n - 1; i >= 1; --i){
		lim = max(0, min(lim - 1, a[i]));
		ans += lim;
	} 
	printf("%lld
", ans);
	return 0;
}

C

所有方案 - 全是红边的方案
并查集维护

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 5;
const ll P = 1e9 + 7;
int n, m; ll ans;
int size[N], fa[N];
inline ll qpow(ll x, ll y){
	ll res = 1;
	while(y){
		if(y & 1) res = res * x % P;
		x = x * x % P; y >>= 1;
	}
	return res;
}
int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}
inline void merge(int x, int y){x = find(x), y = find(y), fa[x] = y, size[y] += size[x];}
int main(){
	scanf("%d%d", &n, &m);
    ans = qpow(n, m);
    for(int i = 1; i <= n; ++i) fa[i] = i, size[i] = 1;
    for(int i = 1, x, y, z; i < n; ++i){
    	scanf("%d%d%d", &x, &y, &z);
    	if(!z) merge(x, y);
    }
    for(int i = 1; i <= n; ++i){
    	if(fa[i] == i){
    		ans = (ans + P - qpow(size[i], m)) % P;
    	}
    }
    printf("%lld
", ans); 
	return 0;
}

然后我就自闭了?

D

给定数m (m leq 1e5)
进行如下流程:
1.rand一个[1, m]的数
2.把它接在序列a后面
3.如果a的gcd等于1 退出 否则进行第一步
求进行流程次数的期望

前面那个(frac{(m-m/x)}{m})是抽到的数不是自己的倍数的概率
(frac{(m-m/x)}{m}*dp[x] = 1 + sum_{d|x}^{m} frac{dp[d]*c[d]}{m})
当然容斥那里用莫比乌斯函数也ok啦【因为懒所以这么写了

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 5;
const ll P = 1e9 + 7;
inline ll qpow(ll x, ll y){
	ll res = 1;
	while(y){
		if(y & 1) res = res * x % P;
		x = x * x % P; y >>= 1;
	}
	return res;
}
int cnt[N], m, invm;
vector<int> d[N];
ll f[N];
inline void init(){
	for(int i = (m >> 1); i > 1; --i)
		for(int j = (i << 1); j <= m; j += i)
			d[j].push_back(i);
	invm = qpow(m, P - 2);
}
inline void cut(int x){
	for(int i : d[x]) cnt[i] -= cnt[x];
}
int main(){
	scanf("%d", &m), init();
	for(int i = 2; i <= m; ++i){
		for(int j : d[i]) cnt[j] = m / j;
		cnt[i] = m / i, cut(i);
		for(int j : d[i]){
			f[i] = (f[i] + f[j] * cnt[j] % P) % P;
			cut(j);
		}
		f[i] = ((f[i] + 1ll * m) % P * qpow(m - m / i, P - 2) % P) % P;
	}
	ll ans = 0;
	for(int i = 2; i <= m; ++i) ans = (ans + f[i]) % P;
	ans = (ans * invm % P + 1) % P;
	printf("%lld", ans);
	return 0;
}

E

有n个点 m个集合
每个点有一个权值pi 有一个集合编号ci
每次删掉一个点之后查询每个集合选一个权值的最大mex
所有数据小于等于5000

倒着加边 边加边匹配

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define mp(x, y) make_pair(x, y)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5005;
int n, m;
struct Edge{int v, next;}edge[N];
int head[N], esize;
inline void addedge(int x, int y){
	edge[++esize] = (Edge){y, head[x]}, head[x] = esize;
}
int p[N], c[N], day[N], ans;
int d, bk[N], match[N];
bool vis[N], del[N];
bool dfs(int x){
	for(int i = head[x], vv; ~i; i = edge[i].next){
		vv = edge[i].v;
		if(!vis[vv]){
			vis[vv] = 1;
			if(!match[vv] || dfs(match[vv])){
				match[vv] = x; return 1;
			}
		}
	}
	return 0;
}
int main(){
	memset(head, -1, sizeof(head));
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", &p[i]), ++p[i];
	for(int i = 1; i <= n; ++i) scanf("%d", &c[i]);
	scanf("%d", &d);
	for(int i = 1; i <= d; ++i) scanf("%d", &bk[i]), del[bk[i]] = 1;
	ans = 1;
	for(int i = 1; i <= n; ++i) if(!del[i]) addedge(p[i], c[i]);
	for(int i = d; i >= 1; --i){ 
    	memset(vis, 0, sizeof(vis));
		while(dfs(ans)){++ans; memset(vis, 0, sizeof(vis));} 
		day[i] = ans - 1;
		addedge(p[bk[i]], c[bk[i]]);
	} 
	for(int i = 1; i <= d; ++i) printf("%d
", day[i]);
	return 0;
}

F(此题解正在施工)

让我们动手算一算
有两个限制(原题中的inc和pref这里叫做c, f)
(p_i leq inc_j leq s_i)
(|b_i - f_j| leq c_j - p_i)
第二个式子可以拆成这样
(b_i >= f_j),那么(b_i - f_j leq c_j - p_i)
(b_i < f_j),那么(f_j - b_i leq c_j - p_i)
然后移位
(b_i >= f_j),那么(b_i + p_i leq c_j + f_j)
(b_i < f_j),那么(p_i - b_i leq c_j - f_j)
然后把第二个式子换一下就是(b_i - p_i geq f_j - c_j)
注意由于(c_j >= p_i),所以在(b_i < f_j时 b_i + p_i leq c_j + f_j)必然成立
然后容斥一下就好了

注意不要重复标记时间戳!unique的返回值十分玄学!

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
int n, m, opsize, lim;
struct OP{
   int tim, d, tag, pos;	
}op[N << 2];
inline bool oprule(OP x, OP y){
	return (x.tim == y.tim) ? (x.tag < y.tag) : (x.tim < y.tim);
}
vector<int> lsh;
int p[N], s[N], b[N], c[N], f[N], ans[N];
int id(ll x){return lower_bound(lsh.begin(), lsh.end(), x) - lsh.begin() + 1;}
struct BIT{
    int w[N << 2];
    void mdf(int x, int d){
        x = id(x);
        while(x <= lim) w[x] += d, x += (x & -x);
	}
    int qry(int x){
    	x = id(x); int res = 0;
    	while(x) res += w[x], x -= (x & -x);
    	return res;
    }
}bit[2];
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", &p[i]);
	for(int i = 1; i <= n; ++i) scanf("%d", &s[i]);
	for(int i = 1; i <= n; ++i){
		scanf("%d", &b[i]);
		op[++opsize] = (OP){p[i], 1, 1, i};
		op[++opsize] = (OP){s[i] + 1, -1, 1, i};//重复标记时间戳! 
	}
	for(int i = 1; i <= m; ++i) scanf("%d", &c[i]);
	for(int i = 1; i <= m; ++i){
		scanf("%d", &f[i]);
		op[++opsize] = (OP){c[i], 0, 2, i};
		lsh.push_back(c[i] + f[i]), lsh.push_back(c[i] - f[i]);
	}
	lsh.push_back(2e9), lsh.push_back(-2e9);
	sort(op + 1, op + opsize + 1, oprule);
	sort(lsh.begin(), lsh.end()); unique(lsh.begin(), lsh.end()), lim = lsh.end() - lsh.begin() + 5;//!!!
	for(int i = 1, cnt = 0, pp; i <= opsize; ++i){
		if(op[i].d) 
		    cnt += op[i].d, pp = op[i].pos, 
			bit[0].mdf(p[pp] + b[pp], op[i].d), 
			bit[1].mdf(p[pp] - b[pp], op[i].d);
		else pp = op[i].pos, ans[pp] = bit[0].qry(c[pp] + f[pp]) + bit[1].qry(c[pp] - f[pp]) - cnt; 
	}
	for(int i = 1; i <= m; ++i) printf("%d ", ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/hjmmm/p/10828662.html