각종 OJ 문제 풀이 기록 6.9 - 6.15
94259 단어 bzoj
[템 플 릿] 다항식 구역
여러 가지 식 으로 역 원 을 구 하 는 오 의 를 배 웠 는데...
고려: B (x) C (x) = 1 (modxn)
항목 이동 및 제곱: B2 (x) C2 (x) − 2B (x) C (x) + 1 = 1 (modx2n)
이 항 획득: B (x) (2C (x) − B (x) C (x)) = 1 (modx2n)
그리고 modx 에서 배로 증가 할 수 있 습 니 다. 복잡 도 O (nlgn)
#include
using namespace std;
const int MAXN = 400005;
const int mod = 998244353, g = 3;
int rev[MAXN];
int power(int a, int n)
{
int ans = 1, b = a;
for (int i = 0; i <= 30; i++) {
if ((n>>i)&1) ans = (long long)ans*b%mod;
b = (long long)b*b%mod;
}
return ans;
}
inline int inv(int a)
{ return power(a, mod-2); }
void NTT(int a[], int n, int flag)
{
int lg = 0;
for (int i = 1; i < n; i<<=1) lg++;
rev[0] = 0;
for (int i = 1; i < n; i++)
rev[i] = (rev[i>>1]>>1)|((i&1)<1));
for (int i = 0; i < n; i++)
if (rev[i]for (int k = 1; k <= n; k <<= 1) {
int dw = power(g, (mod-1)/k);
if (flag == -1) dw = inv(dw);
for (int i = 0; i < n; i += k) {
int w = 1, u, v;
for (int j = 0; j < k>>1; j++) {
u = a[i+j], v = (long long)w*a[i+j+(k>>1)]%mod;
a[i+j] = (u+v)%mod, a[i+j+(k>>1)] = ((u-v)%mod+mod)%mod;
w = (long long)w*dw%mod;
}
}
}
if (flag == -1) {
int iv = inv(n);
for (int i = 0; i < n; i++)
a[i] = (long long)a[i]*iv%mod;
}
}
int tmp[MAXN+MAXN];
void get_inv(int a[], int b[], int n)
{
if (n == 1) {b[0] = inv(a[0]); return; }
get_inv(a, b, n>>1);
memcpy(tmp, a, sizeof(int)*n), memset(tmp+n, 0, sizeof(int)*n);
NTT(tmp, n<<1, 1), NTT(b, n<<1, 1);
for (int i = 0; i < n<<1; i++) b[i] = ((1ll*b[i]*(2-1ll*tmp[i]*b[i]%mod)%mod)+mod)%mod;
NTT(b, n<<1, -1);
memset(b+n, 0, sizeof(int)*n);
// !!!
}
int A[MAXN], B[MAXN], n, m;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%d", &A[i]);
int t = 1;
while (t < m) t <<= 1;
get_inv(A, B, t);
for (int i = 0; i < m; i++)
printf("%d ", (B[i]+mod)%mod);
return 0;
}
꼬마 와 이 진 트 리
프로젝트 수의 생 성 함 수 는 G (z) 이 고 집합 C 의 생 성 함 수 는 C (z) 입 니 다.이 진 트 리 의 형 태 를 고려 하 다.그 는 점 이 하나 밖 에 없 거나 점 하나 와 두 개의 키 로 구성 되 어 있다.즉:
G(z)=G2(z)C(z)+1
해 득: G (z) = 1 ± 1 − 4C (z) √ C (z)
플러스 와 마이너스 번 호 를 고려 하 다.제목 에 c [i] ≥ 1 이 있 기 때문에 오른쪽 에 있 는 분모 상수 항 은 0 이 고 분자 상수 항 만 0 해 가 되 어야 정확 하 다.그래서 부 호 를 취해 야 한다.
분자 유리화
G(z)=21+1−4C(z)−−−−−−−−√
#include
using namespace std;
const int MAXN = (1<<18)+1;
const int mod = 998244353, g = 3;
int rev[MAXN];
int power(int a, int n)
{
int ans = 1, b = a;
for (register int i = 0; i <= 30; i++) {
if ((n>>i)&1) ans = (long long)ans*b%mod;
b = (long long)b*b%mod;
}
return ans;
}
int inv(int a)
{ return power(a, mod-2); }
void NTT(int a[MAXN], int n, int flag)
{
int lg = 0;
for (register int i = 1; i < n; i <<= 1) lg++;
rev[0] = 0;
for (register int i = 0; i < n; i++)
rev[i] = (rev[i>>1]>>1)|((i&1)<1));
for (register int i = 0; i < n; i++)
if (rev[i]for (register int k = 1; k <= n; k <<= 1) {
int dw = power(g, (mod-1)/k);
if (flag == -1) dw = inv(dw);
for (register int i = 0; i < n; i += k) {
int w = 1, u, v;
for (register int j = 0; j < k>>1; j++) {
u = a[i+j], v = (long long)w*a[i+j+(k>>1)]%mod;
a[i+j] = (u+v)%mod, a[i+j+(k>>1)] = ((u-v)%mod+mod)%mod, w = (long long)w*dw%mod;
}
}
}
if (flag == -1) {
int k = inv(n);
for (register int i = 0; i < n; i++)
a[i] = (long long)a[i]*k%mod;
}
}
int tmp_inv[MAXN*2];
void get_inv(int a[], int b[], int n)
{
if (n == 1) { b[0] = inv(a[0]); return;}
get_inv(a, b, n>>1);
memcpy(tmp_inv, a, sizeof(int)*n), memset(tmp_inv+n, 0, sizeof(int)*n);
NTT(tmp_inv, n<<1, 1), NTT(b, n<<1, 1);
for (register int i = 0; i < n<<1; i++)
b[i] = (1ll*b[i]*(2-1ll*tmp_inv[i]*b[i]%mod)%mod+mod)%mod;
NTT(b, n<<1, -1);
memset(b+n, 0, sizeof(int)*n);
}
int tmp_sqrt[MAXN]; // b^{-1}
int tmp_ntt[MAXN];
void get_sqrt(int a[], int b[], int n)
{
if (n == 1) {b[0] = 1; return; }
get_sqrt(a, b, n>>1), memset(tmp_sqrt, 0, sizeof(int)*n*2);
get_inv(b, tmp_sqrt, n);
memcpy(tmp_ntt, a, sizeof(int)*n), memset(tmp_ntt+n, 0, sizeof(int)*n);
NTT(tmp_sqrt, n<<1, 1), NTT(tmp_ntt, n<<1, 1), NTT(b, n<<1, 1);
int val = inv(2);
for (register int i = 0; i < n<<1; i++)
b[i] = (1ll*b[i]*val%mod+1ll*tmp_ntt[i]*tmp_sqrt[i]%mod*val%mod)%mod;
NTT(b, n<<1, -1), memset(b+n, 0, sizeof(int)*n);
}
int C[MAXN], n, m, d[MAXN], e[MAXN], ts[MAXN];
inline int read()
{
int a = 0, c;
do c = getchar(); while(!isdigit(c));
while(isdigit(c)) {
a = a*10+c-'0';
c = getchar();
}
return a;
}
int main()
{
scanf("%d%d", &n, &m);
int t = 1;
while (t <= m) t <<= 1;
for (register int i = 1; i <= n; i++)
C[read()]++;
for (register int i = 0; i < t; i++)
C[i] = ((-4ll*C[i])%mod+mod)%mod;
C[0]++;
get_sqrt(C, d, t);
d[0]++;
get_inv(d, e, t);
for (register int i = 1; i <= m; i++)
printf("%d
", 2ll*e[i]%mod);
return 0;
}
bzoj 4517: [Sdoi 2016] 배열 계수
선형 전달 역 원 을 학습 하 다.http://blog.miskcoo.com/2014/09/linear-find-all-invert
#include
using namespace std;
const int MAXN = 1000005;
const int mod = 1e9+7;
int f[MAXN];
int n, m;
int facd[MAXN], ifac[MAXN], inv_num[MAXN];
void init()
{
inv_num[1] = 1;
for (int i = 2; i < MAXN; i++)
inv_num[i] = (-(long long)(mod/i)*inv_num[mod%i]%mod+mod)%mod;
facd[0] = 1, ifac[0] = 1;
for (int i = 1; i < MAXN; i++) facd[i] = (long long)facd[i-1]*i%mod;
for (int i = 1; i < MAXN; i++) ifac[i] = (long long)ifac[i-1]*inv_num[i]%mod;
// for (int i = 1; i < 10; i++) cout << facd[i] << " "; puts("");
f[0] = 1, f[1] = 0, f[2] = 1;
for (int i = 3; i < MAXN; i++) f[i] = (long long)(i-1)*((f[i-1]+f[i-2])%mod)%mod;
}
inline int choose(int n, int m)
{ return (long long)facd[n]*ifac[m]%mod*ifac[n-m]%mod; }
inline int query(int n, int m)
{ return (long long)choose(n, m)*f[n-m]%mod; }
int main()
{
int T; scanf("%d", &T);
init();
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
if (n < m) puts("0");
else printf("%d
", query(n, m));
}
return 0;
}
bzoj 4403: 서열 통계
L, R 가입 을 고려 한 후 원래 수열 의 차이 점 수 는 10216 ° a0, a2,..., an * 10217 ° 이 고 반드시 만족 할 것 입 니 다.
∑kak=R−L=t
칸막이 법 으로 길이 가 n 인 방안 수 를 분석 하면 다음 과 같다.
(n+tt)
총 프로젝트 수:
∑1≤i≤n(i+tt)=∑1≤i−t≤n(i−t+tt)=∑t지표 로 화 해 를 구하 다.
(∗)=(n+t+1t+1)−(t+1t+1)=(n+t+1t+1)−1
그 다음 에 선형 전달 으로 역 원 을 추구 하고 luca 정리 로 조합 수 를 구하 면 된다.luca 공식 은:
(nm)=(n/pm/p)(n mod pm mod p)
#include
using namespace std;
int T, N, L, R;
const int mod = 1e6+3;
int fac[mod], ifac[mod];
int inv[mod];
inline int choose(int n, int m)
{
if (n < m) return 0;
return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int lucas(int n, int m, int P)
{
if (m == 0) return 1;
return lucas(n/P, m/P, P)*1ll*choose(n%P, m%P)%mod;
}
int main()
{
inv[1] = 1;
for (int i = 2; i < mod; i++) inv[i] = (-1ll*mod/i%mod*inv[mod%i]%mod+mod)%mod;
// for (int i = 1; i <= 10; i++) cerr << 1ll*i*inv[i]%mod << endl;
fac[0] = 1, ifac[0] = 1;
for (int i = 1; i < mod; i++) fac[i] = (long long)fac[i-1]*i%mod;
for (int i = 1; i < mod; i++) ifac[i] = (long long)ifac[i-1]*inv[i]%mod;
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &N, &L, &R);
printf("%d
", (lucas(N+(R-L)+1, N, mod)-1+mod)%mod);
}
return 0;
}
피 카 츄 구출
신 제 는... 전혀 못 해 요.http://hzwer.com/4639.html
#include
using namespace std;
const int MAXN = 506, MAXM = 100005;
struct node {
int to, next, flow, cost, neg;
} edge[MAXM*10];
int head[MAXN], top = 0;
inline void push(int i, int j, int f, int c)
{
// printf("%d--%d--%d->%d
", i, f, c, j);
++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;
++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;
}
const int S = MAXN-2, T = MAXN-3, SS = MAXN-4, ST = MAXN-5;
const int inf = 1e9;
int n, m, k;
void push_lim(int i, int j, int f)
{
push(SS, j, f, 0), push(i, ST, f, 0);
push(i, j, inf, 0);
}
#define IN 0
#define OUT 1
int dis[MAXN], vis[MAXN], pre[MAXN], pre_edge[MAXN];
queue<int> que;
bool spfa(int &flow, int &cost)
{
for (int i = 0; i < MAXN; i++) dis[i] = inf;
// cout << dis[1] << endl;
memset(vis, 0, sizeof vis);
dis[SS] = 0, vis[SS] = 1, que.push(SS);
while (!que.empty()) {
int nd = que.front(); que.pop();
// cout << nd << endl;
//system("sleep 0.5");
vis[nd] = 0;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to, f = edge[i].flow, c = edge[i].cost;
if (!f || dis[to] <= dis[nd]+c) continue;
dis[to] = dis[nd]+c, pre[to] = nd, pre_edge[to] = i;
if (!vis[to])
vis[to] = 1, que.push(to);
}
}
if (dis[ST] >= inf) return 0;
int maxf = INT_MAX;
for (int i = ST; i != SS; i = pre[i]) maxf = min(maxf, edge[pre_edge[i]].flow);
for (int i = ST; i != SS; i = pre[i]) {
edge[pre_edge[i]].flow -= maxf;
edge[edge[pre_edge[i]].neg].flow += maxf;
}
flow += maxf, cost += maxf*dis[ST];
return 1;
}
void mcf(int &flow, int &cost)
{
push(T, S, inf, 0);
flow = cost = 0;
while (spfa(flow, cost));
}
inline int number(int nd, int id)
{
if (nd == 0) return n+n+1;
return nd+id*n;
}
int pw[MAXN], dd[MAXN], tp = 0;
int g[155][155];
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
g[i][j] = inf;
for (int i = 0; i <= n; i++) g[i][i] = 0;
for (int i = 1; i <= m; i++) {
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
g[u][v] = g[v][u] = min(g[u][v], d);
}
for (int k = 0; k <= n; k++)
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++) {
if (k <= i && k <= j)
g[i][j] = min(g[i][j], g[i][k]+g[k][j]);
}
for (int i = 0; i <= n; i++)
for (int j = i+1; j <= n; j++)
if (g[i][j] < inf)
push(number(i, OUT), number(j, IN), inf, g[i][j]);
push(S, number(0, IN), k, 0);
for (int i = 1; i <= n; i++) {
push_lim(number(i, IN), number(i, OUT), 1);
push(number(i, OUT), T, inf, 0);
}
push(number(n, OUT), T, k, 0);
int f = 0, cost = 0;
// puts("---");
mcf(f, cost);
cout << cost << endl;
return 0;
}
bzoj 1212: [HNOI 2004] L 언어
hash 물이 지 나 갔 습 니 다.
#include
using namespace std;
const int MAXN = 1000005;
typedef unsigned long long ull;
set st;
int dp[MAXN];
int n, m;
ull hash_val(char str[])
{
int len = strlen(str);
ull ans = 0;
for (int i = 0; i < len; i++)
ans = ans*31+str[i]-'a'+1;
return ans;
}
char str[25], s[MAXN];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", str);
st.insert(hash_val(str));
// cout << hash_val(str) << endl;
}
for (int i = 1; i <= m; i++) {
memset(dp, 0, sizeof dp);
dp[0] = 1;
scanf("%s", s+1);
int len = strlen(s+1);
for (int j = 1; j <= len; j++) {
ull hav = 0, bs = 1;
// cout << j << endl;
for (int k = j; k >= max(1, j-9); k--) {
hav = hav+bs*(s[k]-'a'+1);
// cout << s[k] << " " << hav << endl;
bs = bs*31;
if (st.count(hav)) {
// printf("%d --> %d
", k-1, j);
dp[j] |= dp[k-1];
}
}
}
int flag = 0;
for (int j = len; j >= 1; j--) {
if (dp[j]) {
printf("%d
", j);
flag = 1;
break;
}
}
if (!flag) puts("0");
}
return 0;
}
AC 자동 해법:
#include
using namespace std;
const int MAXN = 600;
int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0;
int root = 0;
void push(int &nd, const char *str, int len = 0)
{
if (!nd) nd = ++top;
if (*str == '\0') fin[nd] = len;
else push(chl[nd][*str-'a'], str+1, len+1);
}
queue<int> que;
void init()
{
que.push(root), fail[root] = 0;
while (!que.empty()) {
int nd = que.front(); que.pop();
for (int i = 0; i < 26; i++) {
if (!chl[nd][i]) continue;
int p = fail[nd];
while (p && !chl[p][i]) p = fail[p];
if (p) fail[chl[nd][i]] = chl[p][i];
else fail[chl[nd][i]] = root;
que.push(chl[nd][i]);
}
}
}
char s[30], str[1000005];
int n, m;
int dp[1000005];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", s);
push(root, s);
}
init();
for (int i = 1; i <= m; i++) {
memset(dp, 0, sizeof dp);
dp[0] = 1;
scanf("%s", str+1);
int l = strlen(str+1);
int nd = root;
for (int i = 1; i <= l; i++) {
while (nd && !chl[nd][str[i]-'a']) nd = fail[nd];
if (!nd) nd = root;
else nd = chl[nd][str[i]-'a'];
for (int p = nd; p; p = fail[p])
if (fin[p])
dp[i] |= dp[i-fin[p]];
}
int flag = 0;
for (int i = l; i >= 1; i--) {
if (dp[i]) {
flag = 1;
printf("%d
", i);
break;
}
}
if (!flag) printf("0
");
}
return 0;
}
화합물
그냥 폭력 이면 넘 어 가 는 거 야??무슨 귀신
#include
using namespace std;
const int MAXN = 100005, MAXS = 505;
struct node {
int to, next;
} edge[MAXN];
int head[MAXN], top = 0;
inline void push(int i, int j)
{ edge[++top] = (node) {j, head[i]}, head[i] = top; }
int height[MAXN];
int dp[MAXN][MAXS];
long long ans[MAXN*5];
void dfs(int nd)
{
height[nd] = 0, dp[nd][0] = 1;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
dfs(to);
for (int j = 0; j <= height[nd]; j++)
for (int k = 0; k <= height[to]; k++)
ans[j^(k+1)] += (long long)dp[nd][j]*dp[to][k];
height[nd] = max(height[nd], height[to]+1);
for (int j = 0; j <= height[to]; j++)
dp[nd][j+1] += dp[to][j];
}
}
int n;
int main()
{
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
int p; scanf("%d", &p);
push(p, i);
}
dfs(1);
for (int i = 0; ans[i]; i++)
printf("%lld
", ans[i]);
return 0;
}
bzoj 3173: [Tjoi 2013] 최 장 상승 서브 시퀀스
직접 밸 런 스 트 리 를 유지 하면 됩 니 다.하지만 splay 미 친 TLE, treap 가 벼 운 AC...
splay(TLE):
#include
using namespace std;
const int MAXN = 100005;
int chl[MAXN][2], fa[MAXN], dat[MAXN], max_val[MAXN], top = 0;
int siz[MAXN];
int root = 0;
inline void update(int nd)
{
if (!nd) return;
max_val[nd] = dat[nd];
max_val[nd] = max(max(max_val[nd], max_val[chl[nd][0]]), max_val[chl[nd][1]]);
siz[nd] = siz[chl[nd][0]]+siz[chl[nd][1]]+1;
}
inline void zig(int nd)
{
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
int son = chl[nd][tp^1];
fa[son] = (son!=0)*p, chl[g][tg] = (g!=0)*nd;
fa[nd] = g, fa[p] = nd, chl[nd][tp^1] = p, chl[p][tp] = son;
update(p), update(nd);
}
void splay(int nd, int tar_fa = 0)
{
int p, g, tp, tg;
while (fa[nd] != tar_fa) {
p = fa[nd], g = fa[p];
tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (g == tar_fa) { zig(nd); break; }
if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
if (tar_fa == 0) root = nd;
}
int rank_of(int nd)
{
splay(nd);
return siz[chl[nd][0]]+1;
}
inline int find_kth(int k)
{
int nd = root;
while (1) {
if (siz[chl[nd][0]]+1 == k) break;
if (siz[chl[nd][0]]+1 > k) nd = chl[nd][0];
else nd = chl[nd][1], k -= siz[chl[nd][0]]+1;
}
return nd;
}
void insert_in(int k)
{
if (!root)
{ root = ++top, dat[root] = 1, update(root); }
else if (k == 0)
{ splay(find_kth(1)), chl[root][0] = ++top, fa[top] = root, dat[top] = 1, update(top), update(root); }
else if (k == siz[root])
{ splay(find_kth(k)), chl[root][1] = ++top, fa[top] = root, dat[top] = max_val[root]+1, update(top), update(root); }
else {
int nd = find_kth(k), r = find_kth(k+1);
splay(nd), splay(r, root);
chl[r][0] = ++top, fa[top] = r, dat[top] = max(max_val[chl[root][0]], dat[root])+1;
update(top), update(r), update(root);
}
}
int n;
int k;
inline int read()
{
int a = 0, c;
do c = getchar(); while (!isdigit(c));
while (isdigit(c)) {
a = a*10+c-'0';
c = getchar();
}
return a;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
k = read();
insert_in(k);
printf("%d
", max_val[root]);
}
return 0;
}
소모 전
허수 수 를 복습 하 다.
#include
using namespace std;
const int MAXN = 250005;
const long long inf = 23333333333333ll;
struct node {
int to, next, dis;
} edge[MAXN*2], edge_it[MAXN*2];
int head[MAXN], top = 0;
int head_it[MAXN], top_it = 0;
inline void push(int i, int j, int d)
{ edge[++top] = (node){j, head[i], d}, head[i] = top; }
int it_kill_list[MAXN], list_top = 0;
inline void push_it(int i, int j, int d)
{
// printf("%d--%d-->%d
", i, d, j);
if (!head_it[i]) it_kill_list[++list_top] = i;
edge_it[++top_it] = (node) {j, head_it[i], d}, head_it[i] = top_it;
}
int depth[MAXN];
long long len[MAXN];
int fa[MAXN][21], dfn[MAXN], dfn_top = 0;
int out[MAXN], n, m;
void dfs(int nd, int f)
{
fa[nd][0] = f, dfn[nd] = ++dfn_top;
// cerr << nd << " " << dfn_top << endl;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (to == f) continue;
depth[to] = depth[nd]+1, len[to] = min(len[nd], (long long)edge[i].dis);
dfs(to, nd);
}
out[nd] = dfn_top;
}
void init_lca()
{
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
}
int lca(int a, int b)
{
if (depth[a] < depth[b]) swap(a, b);
for (int d = depth[a]-depth[b], i = 0; i <= 20; i++)
if ((d>>i)&1)
a = fa[a][i];
if (a == b) return a;
for (int i = 20; i >= 0; i--)
if (fa[a][i] != fa[b][i])
a = fa[a][i], b = fa[b][i];
return fa[a][0];
}
bool cmp(int a, int b)
{ return dfn[a] < dfn[b]; }
int stk[MAXN], stk_top = 0;
int in_stk[MAXN];
int mark[MAXN];
inline bool in_subtree(int nd, int T)
{ return dfn[nd] >= dfn[T] && dfn[nd] <= out[T];}
void build_tree(vector<int> &pt)
{
sort(pt.begin(), pt.end(), cmp);
// puts("Building tree");
// for (int i = 0; i < pt.size(); i++)
// cerr << dfn[pt[i]] << " ";
// cerr << endl;
for (int i = 0; i < pt.size(); i++)
mark[pt[i]] = 1;
mark[1] = 0;
for (int i = 0; i < pt.size(); i++) {
// cerr << pt[i] << endl;
if (!stk_top) stk[++stk_top] = pt[i], in_stk[pt[i]] = 1;
else {
while (stk_top > 1 && !in_subtree(pt[i], stk[stk_top-1]) &&
!in_subtree(pt[i], stk[stk_top])) {
in_stk[stk[stk_top]] = 0;
push_it(stk[stk_top-1], stk[stk_top], len[stk[stk_top]]);
stk_top--;
// cerr << stk_top << endl;
}
if (in_subtree(pt[i], stk[stk_top])) stk[++stk_top] = pt[i], in_stk[pt[i]] = 1;
else {
int bro = stk[stk_top--], t = lca(bro, pt[i]);
if (!stk_top || t != stk[stk_top]) stk[++stk_top] = t, in_stk[t] = 1;
push_it(stk[stk_top], bro, len[bro]), stk[++stk_top] = pt[i], in_stk[pt[i]] = 1;
}
}
}
while (stk_top > 1) {
// cerr << stk_top << endl;
push_it(stk[stk_top-1], stk[stk_top], len[stk[stk_top]]);
stk_top--;
}
stk_top = 0;
}
long long dfs_dp(int nd, int f)
{
if (mark[nd]) return inf;
long long ans = 0;
for (int i = head_it[nd]; i; i = edge_it[i].next) {
int to = edge_it[i].to, d = edge_it[i].dis;
// cerr << nd << "-->" << d <" << to << endl;
if (to == f) continue;
ans += min((long long)d, dfs_dp(to, nd));
if (ans > inf) ans = inf;
}
return ans;
}
void kill_tree(vector<int> &vec)
{
int num = vec.size();
for (int i = 1; i <= list_top; i++)
head_it[it_kill_list[i]] = 0;
list_top = 0;
top_it = 0;
for (int i = 0; i < num; i++)
mark[vec[i]] = 0;
}
vector<int> vec;
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
push(u, v, d), push(v, u, d);
}
scanf("%d", &m);
for (int i = 1; i <= n; i++) len[i] = inf;
dfs(1, 0), init_lca();
for (int i = 1; i <= m; i++) {
int t, u; scanf("%d", &t);
vec.clear();
vec.push_back(1);
while (t--) {
scanf("%d", &u);
vec.push_back(u);
}
build_tree(vec);
printf("%lld
", dfs_dp(1, 0));
kill_tree(vec);
}
return 0;
}
bzoj 1875: [SDOI 2009] HH 산책 가요.
데이터 범 위 는 우리 에 게 행렬 곱셈 이 라 고 알려 준다.
근 데 왜 돌아 오지 않 는 걸 제한해?
하나의 실행 가능 한 방안 은 변 점 을 교환 한 후에 점 에서 t 번 을 옮 기 면 변 에서 t - 1 번 을 옮 기 고 행렬 을 할 수 있다 는 것 이다.
#include
using namespace std;
const int MAXN = 125, mod = 45989;
int n, m, t, a, b;
struct node {
int from, to, neg;
} edge[MAXN*2];
int top = 0;
struct matrix {
int A[MAXN][MAXN];
void clear()
{ memset(A, 0, sizeof A); }
matrix()
{ clear(); }
friend matrix operator * (const matrix &a, const matrix &b)
{
matrix ret;
for (int i = 1; i <= top; i++)
for (int j = 1; j <= top; j++)
for (int k = 1; k <= top; k++)
(ret.A[i][j] += a.A[i][k]*b.A[k][j]%mod) %= mod;
return ret;
}
} g;
matrix power(matrix a, int p)
{
matrix ans;
for (int i = 1; i <= top; i++)
ans.A[i][i] = 1;
for (int i = 0; i < 31; i++) {
if ((p>>i)&1) ans = ans*a;
a = a*a;
}
return ans;
}
inline void push(int x, int y)
{
++top, edge[top] = (node){x, y, top+1};
++top, edge[top] = (node){y, x, top-1};
}
int c[MAXN], y[MAXN];
void build()
{
for (int i = 1; i <= top; i++) {
for (int j = 1; j <= top; j++) {
if (i != j && j != edge[i].neg && edge[i].to == edge[j].from)
g.A[i][j] = 1;
}
if (edge[i].from == a) c[i]++;
}
}
int main()
{
scanf("%d%d%d%d%d", &n, &m, &t, &a, &b);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
push(u, v);
}
build();
g = power(g, t-1);
for (int i = 1; i <= top; i++) {
for (int j = 1; j <= top; j++)
(y[i] += c[j]*g.A[j][i]) %= mod;
}
int ans = 0;
for (int i = 1; i <= top; i++)
if (edge[i].to == b)
(ans += y[i]) %= mod;
printf("%d
", ans);
return 0;
}
토끼 와 벚꽃
나무 한 그루 를 정 하 다.한 점 을 삭제 하면 이 노드 의 가중치 와 아 이 를 아버지 에 게 걸 고 최대 몇 점 을 삭제 해 야 합 니까?
다음 과 같은 욕심 전략 을 고려 해 키 트 리 를 재 귀적 으로 만 들 고 최대한 많은 아들 을 욕심 내 서 삭제 합 니 다.
이 욕심 은 옳 은 것 이다. 위 에서 노드 를 삭제 하기 위해 아래 의 것 을 삭제 하 는 것 을 포기 할 수 없 기 때문이다.높 은 곳 일수 록 삭제 가 어렵 기 때문에...
#include
using namespace std;
const int MAXN = 2000005;
struct node {
int to, next;
} edge[MAXN*2];
int head[MAXN], top = 0;
inline void push(int i, int j)
{ edge[++top] = (node){j, head[i]}, head[i] = top; }
int n, m;
int chl[MAXN], c[MAXN];
int cnt = 0;
bool cmp(const int a, const int b)
{ return chl[a]+c[a] < chl[b]+c[b]; }
void dfs(int nd)
{
vector<int> vec;
for (int i = head[nd]; i; i = edge[i].next)
dfs(edge[i].to), vec.push_back(edge[i].to);
sort(vec.begin(), vec.end(), cmp);
for (int i = 0; i < vec.size(); i++) {
if (c[nd]+chl[nd]-1+chl[vec[i]]+c[vec[i]] > m) break;
c[nd] += c[vec[i]], chl[nd] += chl[vec[i]]-1;
cnt++;
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &c[i]);
for (int i = 1; i <= n; i++) {
scanf("%d", &chl[i]);
for (int j = 1; j <= chl[i]; j++) {
int v; scanf("%d", &v);
push(i, ++v);
}
}
dfs(1);
printf("%d
", cnt);
return 0;
}
[SDOI 2015] 보물 찾기 게임
나무 사슬 과...
luogu 데이터 가 너무 약 하 잖 아.. 경계 가 안 걸 려..
오리 새끼
#include
using namespace std;
const int MAXN = 200005;
struct node {
int to, next;
long long dis;
} edge[MAXN*2];
int head[MAXN], top = 0;
inline void push(int i, int j, long long d)
{ edge[++top] = (node){j, head[i], d}, head[i] = top; }
int dfn[MAXN], dfn_top = 0;
int depth[MAXN];
long long len[MAXN];
int fa[MAXN][21];
int n, m;
void dfs(int nd, int f)
{
dfn[nd] = ++dfn_top;
depth[nd] = depth[f]+1, fa[nd][0] = f;
for (int i = head[nd]; i; i = edge[i].next) {
if (edge[i].to != f)
len[edge[i].to] = len[nd]+edge[i].dis, dfs(edge[i].to, nd);
}
}
void init()
{
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
}
int lca(int a, int b)
{
if (depth[a] < depth[b]) swap(a, b);
for (int i = 0, d = depth[a]-depth[b]; i <= 20; i++)
if ((d>>i)&1)
a = fa[a][i];
if (a == b) return a;
for (int i = 20; i >= 0; i--)
if (fa[a][i] != fa[b][i])
a = fa[a][i], b = fa[b][i];
return fa[a][0];
}
long long dis(int a, int b)
{
int c = lca(a, b);
return len[a]+len[b]-2*len[c];
}
class cmp {
public:
bool operator () (const int &a, const int &b) const
{ return dfn[a] < dfn[b]; }
};
set<int, cmp, allocator<int> > st;
long long ans = 0;
void insert(int nd)
{
if (st.empty()) { st.insert(nd); return; }
set<int, cmp, allocator<int> >::iterator i = st.upper_bound(nd), j;
if (i == st.begin())
j = st.end(), j--;
else if (i == st.end())
i--, j = st.begin();
else j = i, j--;
// cerr << *i << " " << *j << " -- " << nd << " " << dis(2, 3) << endl;
ans -= dis(*i, *j), ans += dis(*i, nd), ans += dis(*j, nd);
st.insert(nd);
}
void del(int nd)
{
if (st.size() == 1) { st.erase(nd); return; }
set<int, cmp, allocator<int> >::iterator i = st.lower_bound(nd), l, r;
if (i == st.begin())
l = st.end(), l--, r = i, r++;
else if (i == --st.end())
r = st.begin(), l = i, l--;
else l = i, l--, r = i, r++;
ans -= dis(*i, *l), ans -= dis(*i, *r), ans += dis(*l, *r);
st.erase(nd);
}
void deal(int nd)
{
if (st.count(nd)) del(nd);
else insert(nd);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++) {
int u, v;
long long d;
scanf("%d%d%lld", &u, &v, &d);
push(u, v, d), push(v, u, d);
}
dfs(1, 0), init();
for (int i = 1; i <= m; i++) {
int t; scanf("%d", &t);
deal(t);
printf("%lld
", ans);
}
return 0;
}
bzoj 3171 [Tjoi 2013] 순환 격
좋아 하 는 네트워크 스 트림 모델!
무 원 환 실행 가능 흐름 에서 하나의 회 로 는 확장 궤도 이다.이 문제 에 있어 그림 을 교차 하지 않 는 고리 로 만들어 야 한다. 각 노드 의 철거 점 과 유량 을 1 로 제한 하고 방향 을 바 꾸 는 데 비용 이 필요 하 며 원천 송금 이 없 는 최소 비용 으로 흐 르 면 된다.
#include
using namespace std;
const int MAXN = 20;
int g[MAXN][MAXN];
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
int n, m;
char str[MAXN];
struct node {
int to, next, flow, cost, neg;
} edge[MAXN*MAXN*100];
int head[MAXN*MAXN*2], top = 0;
inline void push(int i, int j, int f, int c)
{
// if (i == 18)
// printf("%d--%d,%d-->%d
", i, f, c, j);
++top, edge[top] = (node){j, head[i], f, c, top+1}, head[i] = top;
++top, edge[top] = (node){i, head[j], 0, -c, top-1}, head[j] = top;
}
const int S = MAXN*MAXN*2-4, T = S+1;
inline void push_lim(int i, int j, int flim)
{
push(S, j, flim, 0), push(i, T, flim, 0);
}
int dis[MAXN*MAXN*2], vis[MAXN*MAXN*2];
queue<int> que;
int pre[MAXN*MAXN*2], pre_edge[MAXN*MAXN*2];
const int inf = 23333333;
bool spfa(int &flow, int &cost)
{
memset(dis, 127/3, sizeof dis);
memset(vis, 0, sizeof vis);
vis[S] = 1, dis[S] = 0, que.push(S);
while (!que.empty()) {
int nd = que.front(); que.pop(), vis[nd] = 0;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to, f = edge[i].flow, c = edge[i].cost;
if (!f || dis[to] <= dis[nd]+c) continue;
dis[to] = dis[nd]+c, pre[to] = nd, pre_edge[to] = i;
if (!vis[to])
vis[to] = 1, que.push(to);
}
}
if (dis[T] >= inf) return 0;
int maxf = inf;
for (int i = T; i != S; i = pre[i]) maxf = min(maxf, edge[pre_edge[i]].flow);
// cerr << maxf << " " << dis[T] << endl;
for (int i = T; i != S; i = pre[i]) {
edge[pre_edge[i]].flow -= maxf;
edge[edge[pre_edge[i]].neg].flow += maxf;
// cerr << "Arg : " << pre[i] << "-->"<< i << " Dis = "<< edge[pre_edge[i]].cost << endl;
}
flow += maxf, cost += dis[T]*maxf;
return 1;
}
void mcf(int &flow, int &cost)
{
flow = cost = 0;
while (spfa(flow, cost));
}
inline int number(int i, int j, int id)
{ return (i-1)*m+j+id*(n*m); }
#define IN 0
#define OUT 1
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", str+1);
for (int j = 1; j <= m; j++) {
switch(str[j]) {
case 'U' : g[i][j] = UP; break;
case 'L' : g[i][j] = LEFT; break;
case 'R' : g[i][j] = RIGHT; break;
case 'D' : g[i][j] = DOWN; break;
}
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
push_lim(number(i, j, IN), number(i, j, OUT), 1);
if (g[i][j] == UP) {
push(number(i, j, OUT), number(i>1?i-1:n, j, IN), 1, 0);
push(number(i, j, OUT), number(i1:1, j, IN), 1, 1);
push(number(i, j, OUT), number(i, j>1?j-1:m, IN), 1, 1);
push(number(i, j, OUT), number(i, j<m?j+1:1, IN), 1, 1);
} else if (g[i][j] == DOWN) {
push(number(i, j, OUT), number(i>1?i-1:n, j, IN), 1, 1);
push(number(i, j, OUT), number(i1:1, j, IN), 1, 0);
push(number(i, j, OUT), number(i, j>1?j-1:m, IN), 1, 1);
push(number(i, j, OUT), number(i, j<m?j+1:1, IN), 1, 1);
} else if (g[i][j] == LEFT) {
push(number(i, j, OUT), number(i>1?i-1:n, j, IN), 1, 1);
push(number(i, j, OUT), number(i1:1, j, IN), 1, 1);
push(number(i, j, OUT), number(i, j>1?j-1:m, IN), 1, 0);
push(number(i, j, OUT), number(i, j<m?j+1:1, IN), 1, 1);
} else if (g[i][j] == RIGHT) {
push(number(i, j, OUT), number(i>1?i-1:n, j, IN), 1, 1);
push(number(i, j, OUT), number(i1:1, j, IN), 1, 1);
push(number(i, j, OUT), number(i, j>1?j-1:m, IN), 1, 1);
push(number(i, j, OUT), number(i, j<m?j+1:1, IN), 1, 0);
}
}
int flow, cost;
mcf(flow, cost);
cout << cost << endl;
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
bzoj1010 장난감 포장 [결정 단조성 최적화 dp]하나의 모범 문제라고 할 수 있다.우리는 먼저 소박한 dp방정식을 얻을 수 있다. f[i]=min(f[j]+w(j,i)),j∈[0,i). w(j,i)는 j+1~i를 포장하여 운송하는 비용의 시간 복잡도는 O(n2)라...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.