比赛链接
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;
}