2022NOIPA层联测27

感觉再这么成天咕下去不太好……

 

A. 天平

没有观察到只需要使得选出的砝码质量的gcd与所有砝码的fcd相等即可,但是发现应该让选出的砝码的gcd取到最小值。

我想找到最小的gcd选组成它们的两个数作为起点,以为最小值一定是其中之一,就这么省了个循环但是这个结论是错的所以WA 了,剩下的由【放进去】的假贪心想到每一轮找出一个能使gcd变到最小的选上。

code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 54, inf = 0x3f3f3f3f;

int n, a[maxn], step, mi=inf, id;
bool vis[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

bool check()
{
    for(int i=1; i<=n; i++)
    {
        if(a[i] % mi) return false;
    }
    return true;
}

inline int gcd(int a, int b)
{
    while(b^=a^=b^=a%=b);
    return a;
}

int main()
{
    freopen("weights.in", "r", stdin);
    freopen("weights.out", "w", stdout);
    
    n = read(); 
    for(int i=1; i<=n; i++) 
    {
        a[i] = read();
        if(a[i] < mi) mi = a[i], id = i;
    }
    if(check()) {printf("1\n"); exit(0);}
    int las = mi;
    /*vis[id] = 1; id = 0;
    int las = mi;
    for(int i=1; i<=n; i++)
    {
        if(vis[id]) continue;
        int gd = gcd(a[i], las);
        if(gd < mi) {mi = gd; id = i;}
    }*/
    int m1 = 0, m2 = 0;
    for(int i=1; i<=n; i++)
    {
        for(int j=i+1; j<=n; j++)
        {
            int gd = gcd(a[i], a[j]);
            if(gd < mi) {mi = gd, m1 = i, m2 = j;}
        }
    }
    step = 2; vis[m1] = 1, vis[m2] = 1; id = 0;
    if(check()) {printf("2\n"); exit(0);}
    while(step <= n)
    {
        las = mi;
        for(int i=1; i<=n; i++)
        {
            if(vis[i]) continue;
            int gd = gcd(a[i], las);
            if(gd < mi) {mi = gd; id = i;}
        }
        if(!id) {printf("%d\n", step); break;}
        step++; vis[id] = 1; id = 0;
    }

    return 0;
}

 

B. 支配数据

把序列分成k段让每个序列相互独立线段树及时清空,一开始想把问题拆分:

code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 2, inf = 0x3f3f3f3f;
const int maxQ = 1e7 + 4;

int n, a[maxn], k, Q, ans[maxn], cnt;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct seg 
{
	struct node 
	{
		int v, tag;
	}t[maxn<<2];
	void pushup(int x)
	{
		t[x].v = min(t[x<<1].v, t[x<<1|1].v);
	}
	void build(int x, int l, int r)
	{
		t[x].tag = 0;
		if(l == r)
		{
			t[x].v = a[l]; return;
		}
		int mid = (l + r) >> 1;
		build(x<<1, l, mid);
		build(x<<1|1, mid+1, r);
		pushup(x);
	}
	void pushdown(int x)
	{
		int ls = x<<1, rs = x<<1|1;
		t[ls].v = t[rs].v = t[x].tag;
		t[ls].tag = t[rs].tag = t[x].tag;
		t[x].tag = 0;
	}
	void update(int x, int l, int r, int L, int R, int v)
	{
		if(L <= l && r <= R)
		{
			t[x].v = v; t[x].tag = v;
			return;
		}
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1;
		if(L <= mid) update(x<<1, l, mid, L, R, v);
		if(R > mid) update(x<<1|1, mid+1, r, L, R, v);
		pushup(x);
	}
	int query(int x, int l, int r, int L, int R)
	{
		if(L <= l && r <= R) return t[x].v;
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1, ans = inf;
		if(L <= mid) ans = min(ans, query(x<<1, l, mid, L, R));
		if(R > mid) ans = min(ans, query(x<<1|1, mid+1, r, L, R));
		return ans;
	}
}t;

void solve1()
{
	int N = n * k;
	for(int i=n+1; i<=N; i++) a[i] = a[i-n];
	t.build(1, 1, N);
	Q = read();
	while(Q--)
	{
		int opt = read();
		if(opt == 1)
		{
			int l = read(), r = read(), v = read();
			t.update(1, 1, N, l, r, v);
		}
		else 
		{
			int l = read(), r = read();
			printf("%d\n", t.query(1, 1, N, l, r));
		}
	}
	exit(0);
}

struct ask 
{
	int id, opt, l, r, v, bel;
	bool operator < (const ask &T) const 
	{
		if(bel == T.bel) return id < T.id;
		return bel < T.bel;
	}
}q[maxQ<<2];//依然有可能RE

void split(int now)
{
	int zl = (q[now].l-1)/n+1, zr = (q[now].r-1)/n+1;
	if(zl == zr)
	{
		q[now].l = (q[now].l-1)%n+1, q[now].r = (q[now].r-1)%n+1;
		q[now].bel = zl; return;
	}
	ask res = q[now];
	q[now].r = n; q[now].bel = zl; q[now].l = (res.l-1) % n + 1;
	cnt++; q[cnt] = res;
	q[cnt].l = 1; q[cnt].bel = zr; q[cnt].r = (res.r-1) % n + 1;
	if(zl + 1 == zr) return;
	for(int i=zl+1; i<zr; i++)
	{
		cnt++; q[cnt] = res; 
		q[cnt].l = 1, q[cnt].r = n;
		q[cnt].bel = i;
	}
}

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    
    n = read(); k = read();
	for(int i=1; i<=n; i++) a[i] = read();
	if(n * k <= 1e5) solve1();
	Q = read(); cnt = Q;
	for(int i=1; i<=Q; i++)
	{
		q[i].opt = read(); q[i].id = i;
		q[i].l = read(), q[i].r = read();
		if(q[i].opt == 1) q[i].v = read();
		split(i);
	}
	for(int i=1; i<=Q; i++) 
	{
		if(q[i].opt == 2) ans[i] = inf;
	}
	sort(q+1, q+1+cnt);
	t.build(1, 1, n);
	if(q[1].opt == 1) t.update(1, 1, n, q[1].l, q[1].r, q[1].v);
	else ans[q[1].id] = t.query(1, 1, n, q[1].l, q[1].r);
	for(int i=2; i<=cnt; i++)
	{
		if(q[i].bel != q[i-1].bel) t.build(1, 1, n);
		if(q[i].opt == 1) t.update(1, 1, n, q[i].l, q[i].r, q[i].v);
		else ans[q[i].id] = min(ans[q[i].id], t.query(1, 1, n, q[i].l, q[i].r));
	}
	for(int i=1; i<=Q; i++) 
	{
		if(ans[i]) printf("%d\n", ans[i]);
	}

    return 0;
}

有没有由于数组来不下RE我不知道但是MLE了是真的。后来打算放弃记录问题直接划分:

愉快地T掉了。。。

code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 2, inf = 0x3f3f3f3f;

int n, a[maxn], k, Q, ans[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct seg 
{
	struct node 
	{
		int v, tag;
	}t[maxn<<2];
	void pushup(int x)
	{
		t[x].v = min(t[x<<1].v, t[x<<1|1].v);
	}
	void build(int x, int l, int r)
	{
		t[x].tag = 0;
		if(l == r)
		{
			t[x].v = a[l]; return;
		}
		int mid = (l + r) >> 1;
		build(x<<1, l, mid);
		build(x<<1|1, mid+1, r);
		pushup(x);
	}
	void pushdown(int x)
	{
		int ls = x<<1, rs = x<<1|1;
		t[ls].v = t[rs].v = t[x].tag;
		t[ls].tag = t[rs].tag = t[x].tag;
		t[x].tag = 0;
	}
	void update(int x, int l, int r, int L, int R, int v)
	{
		if(L <= l && r <= R)
		{
			t[x].v = v; t[x].tag = v;
			return;
		}
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1;
		if(L <= mid) update(x<<1, l, mid, L, R, v);
		if(R > mid) update(x<<1|1, mid+1, r, L, R, v);
		pushup(x);
	}
	int query(int x, int l, int r, int L, int R)
	{
		if(L <= l && r <= R) return t[x].v;
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1, ans = inf;
		if(L <= mid) ans = min(ans, query(x<<1, l, mid, L, R));
		if(R > mid) ans = min(ans, query(x<<1|1, mid+1, r, L, R));
		return ans;
	}
}t;

void solve1()
{
	int N = n * k;
	for(int i=n+1; i<=N; i++) a[i] = a[i-n];
	t.build(1, 1, N);
	Q = read();
	while(Q--)
	{
		int opt = read();
		if(opt == 1)
		{
			int l = read(), r = read(), v = read();
			t.update(1, 1, N, l, r, v);
		}
		else 
		{
			int l = read(), r = read();
			printf("%d\n", t.query(1, 1, N, l, r));
		}
	}
	exit(0);
}

struct ask 
{
	int opt, l, r, v;
}q[maxn];

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    
    n = read(); k = read();
	for(int i=1; i<=n; i++) a[i] = read();
	if(n * k <= 1e5) solve1();
	Q = read(); 
	for(int i=1; i<=Q; i++)
	{
		q[i].opt = read(); 
		q[i].l = read(), q[i].r = read();
		if(q[i].opt == 1) q[i].v = read();
	}
	for(int i=1; i<=Q; i++) 
	{
		if(q[i].opt == 2) ans[i] = inf;
	}
	for(int i=1; i<=k; i++)
	{
		t.build(1, 1, n);
		for(int j=1; j<=Q; j++)
		{
			int zl = (q[j].l-1)/n+1, zr = (q[j].r-1)/n+1;
			if(zl > i || zr < i) continue;
			int l = zl == i ? (q[j].l-1)%n+1 : 1, r = zr == i ? (q[j].r-1)%n+1 : n;
			if(q[j].opt == 1) t.update(1, 1, n, l, r, q[j].v);
			else ans[j] = min(ans[j], t.query(1, 1, n, l, r));
		}
	}
	for(int i=1; i<=Q; i++) 
	{
		if(ans[i]) printf("%d\n", ans[i]);
	}

    return 0;
}

比赛结束后就鹤了一下:

建立一棵庞大的动态开点线段树,被覆盖过的在线段树上查,剩下的单独搞个ST表查。

code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e7 + 2, inf = 0x3f3f3f3f;

int n, a[maxn], k, Q, N, rt;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct Table 
{
	int d[maxn][18];
	void init()
	{
		for(int i=1; i<=n; i++) d[i][0] = a[i];
		for(int j=1; (1<<j)<=n; j++)
		{
			for(int i=1; i+(1<<j)-1<=n; i++)
			{
				d[i][j] = min(d[i][j-1], d[i+(1<<j-1)][j-1]);
			}
		}
	}
	int query(int l, int r)
	{
		int k = 0;
		while((1<<k+1) <= r-l+1) k++;
		return min(d[l][k], d[r-(1<<k)+1][k]);
	}
}st;

struct seg 
{
	struct node 
	{
		int v, tag, mv;
	}t[maxn<<2];
	int lc[maxn<<2], rc[maxn<<2];
	int tot;
	void pushup(int x)
	{
		int ans = inf;
		if(lc[x]) ans = t[lc[x]].v;
		if(rc[x]) ans = min(ans, t[rc[x]].v);
		t[x].v = ans;
	}
	void pushdown(int x)
	{
		if(!lc[x]) lc[x] = ++tot;
		if(!rc[x]) rc[x] = ++tot;
		t[lc[x]].tag = t[rc[x]].tag = t[x].tag;
		t[lc[x]].v = t[rc[x]].v = t[x].tag;
		t[lc[x]].mv = t[rc[x]].mv = 1;
		t[x].tag = 0;
	}
	void update(int &x, int l, int r, int L, int R, int v)
	{
		if(!x) x = ++tot;
		if(!rt) rt = x;
		if(L <= l && r <= R)
		{
			t[x].v = v; t[x].tag = v; t[x].mv = 1;
			return;
		}
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1;
		if(L <= mid) update(lc[x], l, mid, L, R, v);
		if(R > mid) update(rc[x], mid+1, r, L, R, v);
		pushup(x);
	}
	int query(int x, int l, int r, int L, int R)
	{
		if(!x && L <= l && r <= R)
		{
			int ll = (l-1)%n+1, rr = (r-1)%n+1;
			int zl = (l-1)/n+1, zr = (r-1)/n+1;
			if(zl == zr) return st.query(ll, rr);
			else return min(st.query(ll, n), st.query(1, rr));
		}
		if(L <= l && r <= R && t[x].mv) return t[x].v;
		if(t[x].tag) pushdown(x);
		int mid = (l + r) >> 1, ans = inf;
		if(L <= mid) ans = min(ans, query(lc[x], l, mid, L, R));
		if(R > mid) ans = min(ans, query(rc[x], mid+1, r, L, R));
		return ans;
	}
}t;

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    
    n = read(); k = read(); N = n * k;
	for(int i=1; i<=n; i++) a[i] = read();
	st.init();
	Q = read();
	while(Q--)
	{
		int opt = read();
		if(opt == 1)
		{
			int l = read(), r = read(), v = read();
			t.update(rt, 1, N, l, r, v);
		}
		else if(opt == 2)
		{
			int l = read(), r = read();
			printf("%d\n", t.query(rt, 1, N, l, r));
		}
	}

    return 0;
}

 

C. 信息学的尽头

我也不知道我就跑了个最短路怎么还MLE 0了!?

然而就假设最短路有分:要不是盲猜CR不会我怎么可能想到了基环树和换根dp之后打算写个暴力不做了

然而她切了%%%CR

不过好像我好好想的话依然想不到具体该怎么办,怎么就连个找环都不会了,怎么就算个贡献都不知道加谁了,%%%CR

无奈至极地去鹤了她的两版code除了函数名之外没什么区别了

同时心情真的很糟糕

code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e5 + 2, inf = 0x3f3f3f3f;

int n, dfn[maxn], num, h[maxn], ccf, fa[maxn], siz[maxn];
ll pdh[maxn], dh[maxn], dep[maxn], sdep[maxn], ans[maxn];
bool inc[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge 
{
    int nxt, to, w;
}e[maxn<<1];
int head[maxn], len;

void add(int x, int y, int w)
{
    e[++len].to = y; e[len].nxt = head[x]; e[len].w = w;
    head[x] = len;
}

void Attend_NOI(int x, int ff)
{
    fa[x] = ff;
    dfn[x] = ++num;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff) continue;
        if(!dfn[v]) pdh[v] = e[i].w, Attend_NOI(v, x);
        else 
        {
            if(dfn[v] < dfn[x])
            {
                int st = x;
                while(st != v)
                {
                    h[++ccf] = st;
                    dh[ccf] = pdh[st];
                    st = fa[st];
                }
                h[++ccf] = v;
                dh[ccf] = e[i].w;
            }
        }
    }
}

void IwantAg(int x, int ff)
{
    sdep[x] = dep[x];
    siz[x] = 1;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff || inc[v]) continue;
        dep[v] = dep[x] + e[i].w;
        IwantAg(v, x);
        siz[x] += siz[v];
        sdep[x] += sdep[v];
    }
}

ll AuIsBest(int pos)
{
    ll ret = 0;
    for(int i=1; i<=ccf; i++)
    {
        if(i == pos) continue;
        ll dev = 0;
        if(i < pos) dev = min(dh[i+ccf]-dh[pos], dh[pos]-dh[i]);
        else dev = min(dh[i+ccf]-dh[pos+ccf], dh[pos+ccf]-dh[i]);
        ret += dev * siz[h[i]];
    }
    return ret;
}

void CTSC(int x, int ff, ll val)
{
    ans[x] = val;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff || inc[v]) continue;
        CTSC(v, x, val+(n-siz[v]*2)*e[i].w);
    }
}

int main()
{
    freopen("end.in", "r", stdin);
    freopen("end.out", "w", stdout);
    
    n = read();
    for(int i=1; i<=n; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w); add(v, u, w);
    }
    Attend_NOI(1, 0);
    for(int i=ccf+1; i>=1; i--) dh[i] = dh[i-1];
    int rp = ccf + 1;
    for(int i=ccf+2; i<=ccf*2; i++)
    {
        rp++; dh[rp] = dh[rp-ccf];
    }
    for(int i=2; i<=ccf*2; i++) dh[i] = dh[i-1] + dh[i];
    for(int i=ccf+1; i<=ccf*2; i++) h[i] = h[i-ccf];
    for(int i=1; i<=ccf*2; i++) inc[h[i]] = 1;
    ll Sum_ep = 0;
    for(int i=1; i<=ccf; i++) IwantAg(h[i], 0), Sum_ep += sdep[h[i]];
    for(int i=1; i<=ccf; i++)
    {
        ll sum_ep = AuIsBest(i);
        sum_ep += Sum_ep;
        CTSC(h[i], 0, sum_ep);
    }
    for(int i=1; i<=n; i++) printf("%lld ", ans[i]);
    
    return 0;
}
code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e5 + 2, inf = 0x3f3f3f3f;

int n, dfn[maxn], num, h[maxn], ccf, fa[maxn], siz[maxn];
ll pdh[maxn], dh[maxn], dep[maxn], sdep[maxn], ans[maxn];
bool inc[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct edge 
{
    int nxt, to, w;
}e[maxn<<1];
int head[maxn], len;

void add(int x, int y, int w)
{
    e[++len].to = y; e[len].nxt = head[x]; e[len].w = w;
    head[x] = len;
}

void Attend_NOI(int x, int ff)
{
    fa[x] = ff;
    dfn[x] = ++num;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff) continue;
        if(!dfn[v]) pdh[v] = e[i].w, Attend_NOI(v, x);
        else 
        {
            if(dfn[v] < dfn[x])
            {
                int st = x;
                while(st != v)
                {
                    h[++ccf] = st;
                    dh[ccf] = pdh[st];
                    st = fa[st];
                }
                h[++ccf] = v;
                dh[ccf] = e[i].w;
            }
        }
    }
}

void IwantAg(int x, int ff)
{
    sdep[x] = dep[x];
    siz[x] = 1;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff || inc[v]) continue;
        dep[v] = dep[x] + e[i].w;
        IwantAg(v, x);
        siz[x] += siz[v];
        sdep[x] += sdep[v];
    }
}

ll ssiz[maxn], sdis[maxn];
ll AuIsBest(int pos)
{
    ll ret = 0;
    /*for(int i=1; i<=ccf; i++)
    {
        if(i == pos) continue;
        ll dev = 0;
        if(i < pos) dev = min(dh[i+ccf]-dh[pos], dh[pos]-dh[i]);
        else dev = min(dh[i+ccf]-dh[pos+ccf], dh[pos+ccf]-dh[i]);
        ret += dev * siz[h[i]];
    }*/
    //又鹤了,,,,,,然而又鹤错了,,,
    int Pos = pos + ccf;
    int l = pos, r = Pos - 1;
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if(dh[mid]-dh[pos] <= dh[Pos]-dh[mid]) l = mid;
        else r = mid - 1;
    }
    if(l > pos) ret = sdis[l]-sdis[pos]-dh[pos]*(ssiz[l]-ssiz[pos]);
    if(l < Pos-1) ret += dh[Pos]*(ssiz[Pos-1]-ssiz[l])-sdis[Pos-1]+sdis[l];
    return ret;
}

void CTSC(int x, int ff, ll val)
{
    ans[x] = val;
    for(int i=head[x]; i; i=e[i].nxt)
    {
        int v = e[i].to;
        if(v == ff || inc[v]) continue;
        CTSC(v, x, val+(n-siz[v]*2)*e[i].w);
    }
}

int main()
{
    freopen("end.in", "r", stdin);
    freopen("end.out", "w", stdout);
    
    n = read();
    for(int i=1; i<=n; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w); add(v, u, w);
    }
    Attend_NOI(1, 0);
    for(int i=ccf+1; i>=1; i--) dh[i] = dh[i-1];
    int rp = ccf + 1;
    for(int i=ccf+2; i<=ccf*2; i++)
    {
        rp++; dh[rp] = dh[rp-ccf];
    }
    for(int i=2; i<=ccf*2; i++) dh[i] = dh[i-1] + dh[i];
    for(int i=ccf+1; i<=ccf*2; i++) h[i] = h[i-ccf];
    for(int i=1; i<=ccf*2; i++) inc[h[i]] = 1;
    ll Sum_ep = 0;
    for(int i=1; i<=ccf; i++) IwantAg(h[i], 0), Sum_ep += sdep[h[i]];
    for(int i=1; i<=ccf*2; i++)
    {
        ssiz[i] = ssiz[i-1] + siz[h[i]];
        sdis[i] = sdis[i-1] + dh[i] * siz[h[i]];
    }
    for(int i=1; i<=ccf; i++)
    {
        ll sum_ep = AuIsBest(i);
        sum_ep += Sum_ep;
        CTSC(h[i], 0, sum_ep);
    }
    for(int i=1; i<=n; i++) printf("%lld ", ans[i]);
    
    return 0;
}

同时依然不服她,%了也不服,输很多次也不服,你就当我是个死鸭子吧,就是化成灰变成烟随风散了也要嘴硬的……

 

D. 球对称薛定谔方程

组织了一下语言发现还是想不出什么和这篇题解不一样的说法,那就……

这种堆的方案数的求法让我想到了多叉堆,公式的差别在于有没有枚举接在一起的另一棵树根节点的权值。关于为什么转移时非要枚举1号点的权值与子树大小,我感觉和有一种二进制拆开的转移让其中一部分减掉lowbit差不多,就是怎么拆都行选一个最好拆的,只是需要枚举了其中一棵子树的信息具体哪棵树并不重要,但是标号最小的儿子权值可以从j+1开始比较方便枚举……

code
 #include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 305, inf = 0x3f3f3f3f;

int n, k, P, C[maxn][maxn], f[maxn][maxn], s[maxn][maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{
    freopen("seq.in", "r", stdin);
    freopen("seq.out", "w", stdout);
    
    n = read(); k = read(); P = read();
	for(int i=0; i<=n; i++)
	{
		C[i][0] = 1;
		for(int j=1; j<=i; j++)
		{
			C[i][j] = ((ll)C[i-1][j] + C[i-1][j-1]) % P;
		}
	}
	for(int i=0; i<=k; i++) f[1][i] = 1, s[1][i] = k-i+1;
	for(int i=2; i<=n+1; i++)
	{
		for(int j=0; j<=k; j++) for(int l=1; l<i; l++) f[i][j] = (f[i][j]+1ll*f[i-l][j]*s[l][j+1]%P*C[i-2][l-1]%P)%P;
		for(int j=k; j; j--) s[i][j] = ((ll)s[i][j+1]+f[i][j])%P;
	}
	printf("%d\n", f[n+1][0]);

    return 0;
}

 

C. 最长路径

顺便add一下我终于把那个TLE 70的做法鹤对了……

code
 /*
怎么鹤还鹤错了呢……
*/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2005;
const int Q = 5e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

int T, n, m, q, f[maxn][maxn], g[maxn][maxn], r[Q][2], c[Q][2];
int L[maxn][maxn], U[maxn][maxn], qug[maxn][maxn], qlg[maxn][maxn];
list<int> qu[maxn], ql[maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct seg 
{
    struct node
    {
        int v, tag;
    }t[maxn<<2];
    void init(int n)
    {
        for(int i=1; i<=4*n; i++)
        {
            t[i].v = t[i].tag = inf;
        }
    }
    void pushdown(int x)
    {
        if(t[x].tag != inf)
        {
            int ls = x<<1, rs = x<<1|1;
            t[ls].tag = min(t[ls].tag, t[x].tag);
            t[rs].tag = min(t[rs].tag, t[x].tag);
            t[ls].v = min(t[ls].v, t[x].tag);
            t[rs].v = min(t[rs].v, t[x].tag);
            t[x].tag = inf;
        }
    }
    void update(int x, int l, int r, int L, int R, int v)
    {
        if(L > R) return;
        if(L <= l && r <= R)
        {
            t[x].tag = min(t[x].tag, v);
            t[x].v = min(t[x].v, v);
            return;
        }
        pushdown(x);
        int mid = (l + r) >> 1;
        if(L <= mid) update(x<<1, l, mid, L, R, v);
        if(R > mid) update(x<<1|1, mid+1, r, L, R, v);
        t[x].v = min(t[x<<1].v, t[x<<1|1].v);
    }
    int query(int x, int l, int r, int pos)
    {
        if(l == r) return t[x].v;
        pushdown(x);
        int mid = (l + r) >> 1;
        if(pos <= mid) return query(x<<1, l, mid, pos);
        else return query(x<<1|1, mid+1, r, pos);
    }
}t[maxn];

void update(int x, int y, int X, int Y)
{
    if(f[x][y] < X + 1) f[x][y] = X + 1, g[x][y] = Y;
    else if(f[x][y] == X + 1) g[x][y] = (g[x][y] + Y) % mod;
}

int main()
{
    freopen("path.in", "r", stdin);
	freopen("path.out", "w", stdout);
    
    T = read();
    while(T--)
    {
        scanf("%d%d%d", &n, &m, &q);
        for(int i=1; i<=q; i++)
        {
            scanf("%d%d%d%d", &r[i][0], &c[i][0], &r[i][1], &c[i][1]);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                f[i][j] = g[i][j] = 1;
            }
        }
        for(int i=1; i<=m; i++) t[i].init(n);
        for(int i=1; i<=q; i++) t[c[i][1]].update(1, 1, n, r[i][0]+1, r[i][1], c[i][0]);
        for(int i=1; i<=n; i++)
        {
            L[i][m+1] = inf;
            for(int j=m; j>=1; j--) L[i][j] = min(t[j].query(1, 1, n, i), L[i][j+1]);
        }
        for(int i=1; i<=n; i++) t[i].init(m);
        for(int i=1; i<=q; i++) t[r[i][1]].update(1, 1, m, c[i][0]+1, c[i][1], r[i][0]);
        for(int i=1; i<=m; i++)
        {
            U[n+1][i] = inf;
            for(int j=n; j>=1; j--) U[j][i] = min(t[j].query(1, 1, m, i), U[j+1][i]);
        }
        for(int i=1; i<=n; i++) ql[i].clear();
        for(int i=1; i<=m; i++) qu[i].clear();
        for(int i=1; i<=max(n,m); i++)
        {
            for(int j=1; j<=max(n,m); j++) qlg[i][j] = qug[i][j] = 0;
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                while(!ql[i].empty() && ql[i].front() < L[i][j])
                {
                    qlg[i][f[i-1][ql[i].front()]] = (qlg[i][f[i-1][ql[i].front()]]-g[i-1][ql[i].front()]+mod)%mod;
                    ql[i].pop_front();
                }
                if(!ql[i].empty()) update(i, j, f[i-1][ql[i].front()], qlg[i][f[i-1][ql[i].front()]]);
                while(!ql[i].empty() && f[i-1][ql[i].back()] < f[i-1][j])
                {
                    qlg[i][f[i-1][ql[i].back()]] = (qlg[i][f[i-1][ql[i].back()]]-g[i-1][ql[i].back()]+mod)%mod;
                    ql[i].pop_back();
                }
                ql[i].push_back(j);
                qlg[i][f[i-1][j]] = (qlg[i][f[i-1][j]]+g[i-1][j])%mod;
                while(!qu[j].empty() && qu[j].front() < U[i][j])
                {
                    qug[j][f[qu[j].front()][j-1]] = (qug[j][f[qu[j].front()][j-1]]-g[qu[j].front()][j-1]+mod)%mod;
                    qu[j].pop_front();
                }
                if(!qu[j].empty()) update(i, j, f[qu[j].front()][j-1], qug[j][f[qu[j].front()][j-1]]);
                if(i != 1)
                {
                    while(!qu[j].empty() && f[qu[j].back()][j-1] < f[i-1][j-1])
                    {
                        qug[j][f[qu[j].back()][j-1]] = (qug[j][f[qu[j].back()][j-1]]-g[qu[j].back()][j-1]+mod)%mod;
                        qu[j].pop_back();
                    }
                    qu[j].push_back(i-1);
                    qug[j][f[i-1][j-1]] = (qug[j][f[i-1][j-1]]+g[i-1][j-1])%mod;
                }
            }
        }
        int ans1 = 0, ans2 = 0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=m; j++)
            {
                if(f[i][j] > ans1) ans1 = f[i][j], ans2 = g[i][j];
                else if(f[i][j] == ans1) ans2 = (ans2 + g[i][j]) % mod;
            }
        }
        printf("%d %d\n", ans1, ans2);
    }

    return 0;
}

 

posted @ 2022-11-14 07:48  Catherine_leah  阅读(20)  评论(1编辑  收藏  举报
/* */