纪念(ˇˍˇ) 想~
B
题意:树上的两个操作
一、对路径上的边权进行修改
二、求路径上边权连续的段数
思路:树链剖分操作,小心边界。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 4e4 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
struct Tree {
int l, r, sum, lc, rc, lazy;
};
Tree tree[MAXN << 2];
void PushUp(int o){
tree[o].sum = tree[ll].sum + tree[rr].sum;
tree[o].lc = tree[ll].lc; tree[o].rc = tree[rr].rc;
if(tree[ll].rc == tree[rr].lc) tree[o].sum--;
}
void PushDown(int o) {
if(tree[o].lazy != -1) {
tree[ll].lazy = tree[rr].lazy = tree[o].lazy;
tree[ll].lc = tree[ll].rc = tree[rr].lc = tree[rr].rc = tree[o].lazy;
tree[ll].sum = tree[rr].sum = 1;
tree[o].lazy = -1;
}
}
void Build(int o, int l, int r) {
tree[o].l = l; tree[o].r = r;
tree[o].lc = tree[o].rc = -1, tree[o].sum = 0; tree[o].lazy = -1;
if(l == r) return ;
int mid = (l + r) >> 1;
Build(ll, l, mid); Build(rr, mid + 1, r);
}
void Update(int o, int L, int R, int v) {
if(tree[o].l == L && tree[o].r == R) {
tree[o].lc = tree[o].rc = v;
tree[o].sum = 1; tree[o].lazy = v;
return ;
}
PushDown(o);
int mid = (tree[o].l + tree[o].r) >> 1;
if(R <= mid) Update(ll, L, R, v);
else if(L > mid) Update(rr, L, R, v);
else {Update(ll, L, mid, v); Update(rr, mid+1, R, v);}
PushUp(o);
}
int Query(int o, int L, int R) {
if(tree[o].l == L && tree[o].r == R) {
return tree[o].sum;
}
PushDown(o);
int mid = (tree[o].l + tree[o].r) >> 1;
if(R <= mid) return Query(ll, L, R);
else if(L > mid) return Query(rr, L, R);
else return Query(ll, L, mid) + Query(rr, mid + 1, R) - (tree[ll].rc == tree[rr].lc);
}
int Color(int o, int pos) {
if(tree[o].l == tree[o].r) {
return tree[o].lc;
}
PushDown(o);
int mid = (tree[o].l + tree[o].r) >> 1;
if(pos <= mid) return Color(ll, pos);
else return Color(rr, pos);
}
struct Edge {
int from, to, next;
};
Edge edge[MAXN * 2];
int head[MAXN], edgenum;
void init() { edgenum = 0; CLR(head, -1); }
void addEdge(int u, int v) {
Edge E = {u, v, head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
int son[MAXN], num[MAXN];
int top[MAXN], pos[MAXN], id;
int dep[MAXN], pre[MAXN];
void DFS1(int u, int fa, int d) {
dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(v == fa) continue;
DFS1(v, u, d + 1);
num[u] += num[v];
if(son[u] == -1 || num[son[u]] < num[v]) {
son[u] = v;
}
}
}
void DFS2(int u, int T) {
top[u] = T; pos[u] = ++id;
if(son[u] == -1) return ;
DFS2(son[u], T);
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(v == pre[u] || v == son[u]) continue;
DFS2(v, v);
}
}
int GetSum(int u, int v) {
if(u == v) return 0;
int f1 = top[u], f2 = top[v];
int ans = 0;
int lastu = -1, lastv = -1;
while(f1 != f2) {
if(dep[f1] < dep[f2]) {
ans += Query(1, pos[f2], pos[v]);
int C = Color(1, pos[v]);
if(lastv == C) {
ans--;
}
lastv = Color(1, pos[f2]);
v = pre[f2]; f2 = top[v];
}
else {
ans += Query(1, pos[f1], pos[u]);
int C = Color(1, pos[u]);
if(lastu == C) {
ans--;
}
lastu = Color(1, pos[f1]);
u = pre[f1]; f1 = top[u];
}
}
if(u == v) return ans - (lastu == lastv);
if(dep[u] > dep[v]) {
ans += Query(1, pos[son[v]], pos[u]);
if(lastu == Color(1, pos[u])) {
ans--;
}
if(lastv == Color(1, pos[son[v]])) {
ans--;
}
}
else {
ans += Query(1, pos[son[u]], pos[v]);
if(lastu == Color(1, pos[son[u]])) {
ans--;
}
if(lastv == Color(1, pos[v])) {
ans--;
}
}
return ans;
}
void Change(int u, int v, int z) {
int f1 = top[u], f2 = top[v];
while(f1 != f2) {
if(dep[f1] < dep[f2]) {
swap(u, v);
swap(f1, f2);
}
Update(1, pos[f1], pos[u], z);
u = pre[f1], f1 = top[u];
}
if(u == v) return ;
if(dep[u] > dep[v]) swap(u, v);
Update(1, pos[son[u]], pos[v], z);
}
int s[MAXN], e[MAXN], c[MAXN];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
init();
for(int i = 1; i <= n - 1; i++) {
scanf("%d%d%d", &s[i], &e[i], &c[i]);
addEdge(s[i], e[i]); addEdge(e[i], s[i]);
}
DFS1(1, -1, 1); id = 0; DFS2(1, 1); Build(1, 1, id);
for(int i = 1; i <= n - 1; i++) {
if(dep[s[i]] > dep[e[i]]) {
swap(s[i], e[i]);
}
Update(1, pos[e[i]], pos[e[i]], c[i]);
}
while(m--) {
char op[10]; scanf("%s", op); int x, y, z;
if(op[0] == 'C') {
scanf("%d%d%d", &x, &y, &z);
Change(x, y, z);
}
else {
scanf("%d%d", &x, &y);
printf("%d\n", GetSum(x, y));
}
}
}
return 0;
}
C
题意:
n
个不同的位置,
思路:我们先每隔
第一个和第二个不要写反了······
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 3e6 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
LL fac[MAXN];
LL pow_mod(LL a, int n) {
LL ans = 1;
while(n) {
if(n & 1) {
ans = ans * a % MOD;
}
a = a * a % MOD;
n >>= 1;
}
return ans;
}
LL C(LL n, LL m) {
return fac[n] * pow_mod(fac[n - m], MOD - 2) % MOD * pow_mod(fac[m], MOD - 2) % MOD;
}
int main()
{
fac[0] = 1;
for(int i = 1; i <= MAXN - 1; i++) {
fac[i] = fac[i - 1] * i % MOD;
}
int t; scanf("%d", &t);
while(t--) {
int n, m, k; scanf("%d%d%d", &n, &m, &k);
int x = n - m * (k + 1);
if(m == 1) {
printf("%d\n", n);
}
else if(x < 0) {
printf("0\n");
}
else {
printf("%lld\n", C(x + m - 1, m - 1) * n % MOD * pow_mod(m, MOD - 2) % MOD);
}
}
return 0;
}
C
题意:
f(0)=0,f(1)=1,f(n)=f(n−2)+2∗f(n−1)(n≥2)
g(n)=∑ni=0f(i)2
。求解
xg(n∗y)%(s+1)
.
思路:由欧拉定理
aphi(b)==1(modb)
则有
ac%b=ac%phi(b)%b
g(n)=g(n−1)+f(n)2
f(n)2=(f(n−2)+2∗f(n−1))2
f(n)2=f(n−2)2+4∗f(n−1)∗f(n−2)+4∗f(n−1)2
f(n−1)∗f(n−2)=(f(n−3)+2∗f(n−2))∗f(n−2)
f(n−1)∗f(n−2)=2∗f(n−2)2+f(n−2)∗f(n−3)
维护
f(n)∗f(n−1),f(n−1)2,f(n)2,g[n]
,然后矩阵加速即可。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 2e6 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
//const int MOD = 1e9 + 7;
LL MOD;
void add(LL &x, LL y) { x += y; x %= MOD; }
LL gcd(LL a, LL b) {
return b == 0 ? a : gcd(b, a % b);
}
struct Ma {
LL a[4][4];
};
Ma multi(Ma x, Ma y) {
Ma z; CLR(z.a, 0);
for(int i = 0; i < 4; i++) {
for(int k = 0; k < 4; k++) {
if(x.a[i][k] == 0) continue;
for(int j = 0; j < 4; j++) {
add(z.a[i][j], x.a[i][k] * y.a[k][j] % MOD);
}
}
}
return z;
}
LL Solve(Ma x, LL n) {
if(n == 0) return 0;
if(n == 1) return 1;
if(n == 2) return 5;
n -= 2;
Ma y; CLR(y.a, 0);
for(int i = 0; i < 4; i++) {
y.a[i][i] = 1;
}
while(n) {
if(n & 1LL) {
y = multi(x, y);
}
x = multi(x, x);
n >>= 1;
}
return (((y.a[0][3] + 2 * y.a[1][3] % MOD) % MOD + 4 * y.a[2][3] % MOD) % MOD + 5 * y.a[3][3] % MOD) % MOD;
}
LL pow_mod(LL a, LL n, int p) {
LL ans = 1LL;
while(n) {
if(n & 1LL) {
ans = ans * a % p;
}
a = a * a % p;
n >>= 1LL;
}
return ans;
}
LL euler(LL n) {
LL ans = n;
for(LL i = 2; i * i <= n; i++) {
if(n % i == 0) {
ans = ans / i * (i - 1);
while(n % i == 0) {
n /= i;
}
}
}
if(n > 1) {
ans = ans / n * (n - 1);
}
return ans;
}
int main()
{
int t; scanf("%d", &t);
while(t--) {
LL n, y, x, s;
scanf("%lld%lld%lld%lld", &n, &y, &x, &s);
MOD = euler(s + 1);
Ma X;
X.a[0][0] = 0; X.a[0][1] = 0; X.a[0][2] = X.a[0][3] = 1;
X.a[1][0] = 0; X.a[1][1] = 1; X.a[1][2] = X.a[1][3] = 4;
X.a[2][0] = 1; X.a[2][1] = 2; X.a[2][2] = X.a[2][3] = 4;
X.a[3][0] = X.a[3][1] = X.a[3][2] = 0; X.a[3][3] = 1;
LL ans = pow_mod(x, Solve(X, n * y), s + 1);
printf("%lld\n", ans);
}
return 0;
}
G
题意:奇偶数定义——连续偶数个奇数或者连续奇数个偶数,问你区间
[L,R]
奇偶数个数。
思路:数位
dp
,
dp[i][j][k]
表示处理到第
i
个位置当前位置填数字
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 5e5 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
LL dp[20][10][20];
int a[20];
LL DFS(int pos, int now, int num, int yes) {
//cout << pos << ' ' << now << ' ' << num << endl;
if(pos == -1) {
if(num == 0) return 0LL;
if(now & 1) {
if(num & 1) return 0LL;
else return 1LL;
}
else {
if(num & 1) return 1LL;
else return 0LL;
}
}
if(!yes && dp[pos][now][num] != -1) return dp[pos][now][num];
int End = yes ? a[pos] : 9;
LL ans = 0;
for(int i = 0; i <= End; i++) {
if(num == 0) {
if(i == 0) {
ans += DFS(pos - 1, i, 0, yes && i == End);
}
else {
ans += DFS(pos - 1, i, 1, yes && i == End);
}
continue;
}
if(now & 1) {
if(i % 2 == 0) {
if(num & 1) continue;
ans += DFS(pos - 1, i, 1, yes && i == End);
}
else {
ans += DFS(pos - 1, i, num + 1, yes && i == End);
}
}
else {
if(i & 1) {
if(num % 2 == 0) continue;
ans += DFS(pos - 1, i, 1, yes && i == End);
}
else {
ans += DFS(pos - 1, i, num + 1, yes && i == End);
}
}
}
if(!yes) dp[pos][now][num] = ans;
return ans;
}
LL Count(LL n) {
int len = 0;
while(n) {
a[len++] = n % 10;
n /= 10;
}
return DFS(len - 1, 0, 0, 1);
}
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
LL L, R; scanf("%lld%lld", &L, &R);
CLR(dp, -1);
printf("Case #%d: %lld\n", kcase++, Count(R) - Count(L - 1));
}
return 0;
}
I
题意:给定
N
个数字,每次若相邻的数字
思路:区间
dp
,枚举中间点,但是注意头尾的判断。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 300 + 10;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
bool vis[MAXN][MAXN];
LL dp[MAXN][MAXN];
LL gcd(LL a, LL b) {
return b == 0 ? a : gcd(b, a % b);
}
LL a[MAXN], b[MAXN], sum[MAXN];
LL DFS(int l, int r) {
if(dp[l][r] != -1) return dp[l][r];
if(l >= r) return dp[l][r] = 0;
if(l + 1 == r) {
if(vis[l][r]) {
return dp[l][r] = b[l] + b[r];
}
else {
return dp[l][r] = 0;
}
}
LL ans = 0;
if(vis[l][r]) {
ans = DFS(l + 1, r - 1);
if(sum[r - 1] - sum[l] == ans) {
ans += b[l] + b[r];
}
}
for(int k = l; k < r; k++) {
ans = max(ans, DFS(l, k) + DFS(k + 1, r));
}
dp[l][r] = ans;
return ans;
}
int main()
{
int t; scanf("%d", &t);
while(t--) {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
CLR(vis, false);
for(int i = 1; i <= n; i++) {
for(int j = i; j <= n; j++) {
if(gcd(a[i], a[j]) != 1) {
vis[i][j] = true;
}
}
}
sum[0] = 0;
for(int i = 1; i <= n; i++) {
scanf("%lld", &b[i]);
sum[i] = sum[i - 1] + b[i];
}
CLR(dp, -1);
printf("%lld\n", DFS(1, n));
}
return 0;
}
J
题意:问你
<=N
<script type="math/tex" id="MathJax-Element-35"><=N</script>的素数个数。
论文题目?
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cstdlib>
#define ll o<<1
#define rr o<<1|1
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int INF = 1e9 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) { x += y; x %= MOD; }
using namespace std;
const int MAXN = 100;
const int MAXM = 20010;
#define chkbit(ar, i) (((ar[(i) >> 6]) & (1 << (((i) >> 1) & 31))))
#define setbit(ar, i) (((ar[(i) >> 6]) |= (1 << (((i) >> 1) & 31))))
#define isprime(x) (( (x) && ((x)&1) && (!chkbit(ar, (x)))) || ((x) == 2))
LL dp[MAXN][MAXM];
//dp[n][m]表示区间[1, m]里面不被前n个素数任意一个整除的个数
//dp[0][m] = m;
//dp[n][m] = dp[n - 1][m] - dp[n - 1][m / p[n]]
unsigned int ar[(10000010 >> 6) + 5] = {0};
int len = 0, p[1000000], num[10000010];
LL phi(LL m, int n) {
if(n == 0) return m;
if(p[n - 1] >= m) return 1;
if(m < MAXM && n < MAXN) return dp[n][m];
return phi(m, n - 1) - phi(m / p[n - 1], n - 1);
}
LL Lehmer(LL m) {
if(m < 10000010) return num[m];
int s = sqrt(0.9 + m);
int y = cbrt(0.9 + m); int c = y;
int a = num[y];
LL res = phi(m, a) + a - 1;
for(int i = a; p[i] <= s; i++) {
res = res - Lehmer(m / p[i]) + Lehmer(p[i]) - 1;
}
return res;
}
int main()
{
setbit(ar, 0), setbit(ar, 1);
for(int i = 3; (i * i) < 10000010; i++, i++) {
if(!chkbit(ar, i)) {
int k = i << 1;
for(int j = (i * i); j < 10000010; j += k) setbit(ar, j);
}
}
for(int i = 1; i < 10000010; i++) {
num[i] = num[i - 1];
if(isprime(i)) p[len++] = i, num[i]++;
}
for(int i = 0; i < MAXN; i++) {
for(int j = 0; j < MAXM; j++) {
if(!i) dp[i][j] = j;
else dp[i][j] = dp[i - 1][j] - dp[i - 1][j / p[i - 1]];
}
}
LL n;
while(scanf("%lld", &n) != EOF) {
printf("%lld\n", Lehmer(n));
}
return 0;
}