[2020牛客NOIP赛前集训营-提高组(第三场)] 补题

A.牛半仙的妹子数

Problem

题目链接

Soluiton

  • 思维 / 数学

首先观察到左边的数之和为 (a+b),令其为 (x),右边的数为 (c),令其为 (y)。并且左边加右边的和为定值 (a+b+c),令 (s=a+b+c)

(x+y = s)

如果 (x>y),则 (x = x - y,y = 2y)。此时 (2y<s),所以 (2yequiv 2y pmod{s}) (1)(可能看起来有点别扭)

否则 (x le y),则 (x = 2x, y = y - x)。此时 (2y>s,y = y - x = y - s + y = 2y-s),所以 (2y equiv 2y-s pmod{s}) (2)。

又因为在 (1) 式中 (0 le 2y < s),在 (2) 式中 (0 le 2y-s < s),我们可以认为答案就是 (2^ky mod s)

用快速幂,时间复杂度 (O(T log k))

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
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<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int a,b,c,k,mod;
int Pow(int x,int y) {
	int res = 1, base = x;
	while(y) {
		if(y&1) res = res*base%mod; base = base*base%mod; y >>= 1;
	}
	return res;
}
void work() {
	a = read(), b = read(), c = read(), k = read();
	mod = a + b + c;
	printf("%lld
",Pow(2,k)*c%mod);
}
signed main()
{
	int T = read();
	while(T--) work();
   	return 0;
}

B.牛半仙的妹子图

Problem

题目地址

Solution

  • SPFA

本题是稀疏图(ygt大佬说网格图是稀疏图可以卡掉SPFA),可以用 SPFA 处理从 s 到 i 的所有路径里面最大边最小是多少,记为 dismx[ i ]。然后按照题意模拟,统计一下答案,输出即可。时间复杂度 (O(km + q log 600))(O(km)) 是SPFA的复杂度,可以过)

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
using namespace std;
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<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 5e5+7, M = 607;
int n,m,q,s,mod,opt,cnt,tot,ntmp;
int c[N],head[N],dismx[N],ma[M],sum[M],cal[M],btmp[N];
bool flag[N];
struct Edge {
	int next,to,w;
}edge[N<<1];
void add(int u,int v,int w) {
	edge[++cnt] = (Edge)<%head[u],v,w%>;
	head[u] = cnt;
}
void SPFA() {
	bool vis[N];
	queue<int> q;
	memset(dismx, 0x3f, sizeof(dismx));
	memset(vis, 0, sizeof(vis));
	dismx[s] = 0; q.push(s); vis[s] = 1;
	while(!q.empty()) {
		int u = q.front(); vis[u] = 0; q.pop();
		//if(u == n) printf("??? %d ???
",dismx[u]);
		for(int i=head[u];i;i=edge[i].next) {
			int v = edge[i].to, w = edge[i].w;
			if(dismx[v] > max(dismx[u],w)) {
				dismx[v] = max(dismx[u],w);
				if(!vis[v]) {
					q.push(v); vis[v] = 1;
				}
			}
		}
	}
}
int Get1(int x) {
	int l = 1, r = ntmp, mid, ans = ntmp + 1;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(btmp[mid] >= x) {
			ans = mid; r = mid - 1;
		} else l = mid + 1;
	}
	return ans;
}
int Get2(int x) {
	int l = 1, r = ntmp, mid, ans = 0;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(btmp[mid] <= x) {
			ans = mid; l = mid + 1;
		} else r = mid - 1;
	}
	return ans;
}
signed main()
{
	//freopen("sample.in","r",stdin);
	//freopen("x.txt","w",stdout);
	n = read(), m = read(), q = read(), s = read(), opt = read();
	if(opt == 1) mod = read();
	for(int i=1;i<=n;++i) c[i] = read();
	for(int i=1;i<=m;++i) {
		int u = read(), v = read(), w = read();
		add(u,v,w), add(v,u,w);
	}
	SPFA();
	/*cout << "dismx" << endl;
	for(int i=1;i<=n;++i) printf("%d ",dismx[i]);
	cout << endl << endl;*/
	memset(ma, 0x3f, sizeof(ma));
	int INF = ma[0];
	for(int i=1;i<=n;++i) {
		ma[c[i]] = min(ma[c[i]], dismx[i]);
		if(!flag[c[i]] && dismx[i]!=INF) {
			++tot; flag[c[i]] = 1;
		}
	}
	sort(ma+1, ma+1+600);
	for(int i=1;i<=600;++i) btmp[i] = ma[i];
	ntmp = unique(btmp+1, btmp+1+tot) - btmp - 1;
	for(int i=1;i<=tot;++i) {
		int x = lower_bound(btmp+1, btmp+1+ntmp, ma[i]) - btmp;
		//printf("%d ",x);
		++cal[x];
	}
	/*printf("btmp-ma:
");
	for(int i=1;i<=ntmp;++i) printf("%d ",btmp[i]);
	cout << endl;
	printf("cal:
");
	for(int i=1;i<=ntmp;++i) printf("%d ",cal[i]);
	cout << endl;*/
	for(int i=1;i<=ntmp;++i) cal[i] += cal[i-1];
	for(int i=1;i<ntmp;++i) sum[i] = sum[i-1] + cal[i]*(btmp[i+1]-btmp[i]);
	/*printf("sum:
");
	for(int i=1;i<ntmp;++i) printf("%d ",sum[i]);
	cout << endl << endl;*/
	int ans = 0;
	while(q--) {
		int l = read(), r = read();
		if(opt == 1) {
			l = (l xor ans) % mod + 1;
			r = (r xor ans) % mod + 1;
			if(l > r) swap(l, r);
		}
		ans = 0;
		int ml = Get1(l), mr = Get2(r);
		//printf(" %d %d
",ml,mr);
		if(mr == 0) ans = 0;
		else if(ml == ntmp+1) ans = (r - l + 1) * tot;
		else {
			//printf(" %d %d
",ml,mr);
			ans += (btmp[ml] - l) * (cal[ml-1]);
			ans += (sum[mr-1] - sum[ml-1]);
			ans += (r - btmp[mr]+1) * cal[mr];
		}
		printf("%lld
",ans);
	}
	return 0;
}
/*
8 15 1 1 0
4 3 4 2 3 1 2 1 
1 2 7
1 3 6
1 4 6
3 5 13
1 6 13
5 7 8
4 8 15
4 3 15
7 3 9
2 4 13
6 7 7
8 1 5
5 8 14
6 8 3
6 5 5
0 27

96
*/

C.牛半仙的妹子Tree

Problem

题目链接

Solution

  • ST表求LCA((O(n log n)) 预处理,(O(1)) 查询,常数较大)

  • 操作分块思想

以清空操作为分界点,把操作序列分成 (k) 块。

  1. 对于一个大小为 s 的块,且用 lca法 判断查询操作:最劣的情况下有 (frac{s}{2}) 个加入操作,(frac{s}{2}) 个查询操作,lca法 判断一个点的复杂度是 (O(1)),故判断 (frac{s}{2}) 个点的复杂度是 (O(frac{s}{2})),该块的所有操作复杂度 (O(frac{s^2}{4})),由于 lca法 的常数较大,可以把复杂度近似为 (O(s^2))

  2. 对于一个大小为 s 的块,且用 bfs法 判断查询操作:复杂度 (O(n))

对于以上两种方法的分析,于是我们可以:

对于一个大小大于 (sqrt{m}) 的块,用 bfs法 判断查询操作,块内总复杂度 (O(n)),均摊到每个查询操作上 (O(sqrt{n}))

对于一个大小小于 (sqrt{m}) 的块,有 lca法 判断查询操作,每个查询操作复杂度 (O(sqrt{m}))

对于所有查询操作,总时间复杂度 (O(nsqrt{n})) 级别。(n le 10^5),可以通过。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
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<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
typedef pair<int,int> PII;
const int N = 1e5+7;
int n,m,cnt,dcnt,qcnt;
int head[N],dep[N],dfn[N<<1],pos[N],ST[N<<1][20],lg[N<<1],opt[N],X[N],qs[N],qt[N],id[N<<1];
vector<int> ans;
struct Edge {
    int next,to;
}edge[N<<1];
inline void add(int u,int v) {
    edge[++cnt] = (Edge)<%head[u],v%>;
    head[u] = cnt;
}
void Dfs(int u,int fa) {
    dep[u] = dep[fa] + 1;
    ++dcnt; dfn[dcnt] = dcnt; pos[u] = dcnt; id[dcnt] = u;
    for(int i=head[u];i;i=edge[i].next) {
        int v = edge[i].to;
        if(v != fa) {
            dfn[++dcnt] = pos[u]; Dfs(v,u);
        }
    }
}
void Init() {
    for(int i=2;i<=dcnt;++i) lg[i] = lg[i>>1] + 1;
    for(int i=1;i<=dcnt;++i) ST[i][0] = dfn[i];
    for(int j=1;j<20;++j) {
        for(int i=1;i+(1<<j)-1<=dcnt;++i) {
            ST[i][j] = min(ST[i][j-1], ST[i+(1<<(j-1))-1][j-1]);
        }
    }
}
int dist(int x,int y) {
    int px = pos[x], py = pos[y];
    if(px > py) swap(px,py);
    int L = py - px + 1;
    int lca = id[min(ST[px][lg[L]], ST[py-(1<<lg[L])+1][lg[L]])];
    return dep[x] + dep[y] - 2*dep[lca];
}
void Calc1(int s,int t) {
    vector<PII> ma;
    for(int i=s;i<t;++i) {
        if(opt[i] == 1) {
            ma.pb(mp(X[i],i));
        } else {
            bool flag = 0;
            for(int k=0;k<ma.size();++k) {
                if(dist(ma[k].fi, X[i]) <= i-ma[k].se) {
                    flag = 1; break;
                }
            }
            ans.pb(flag);
        }
    }
}
void Calc2(int s,int t) {
    bool vis[N]; queue<int> q;
    memset(vis, 0, sizeof(vis));
    for(int i=s;i<t;++i) {
        int step = q.size();
        while(step--) {
            int u = q.front(); q.pop();
            for(int i=head[u];i;i=edge[i].next) {
                int v = edge[i].to;
                if(!vis[v]) {
                    vis[v] = 1; q.push(v);
                }
            }
        }
        if(opt[i] == 1) vis[X[i]] = 1, q.push(X[i]);
        else ans.pb(vis[X[i]]);
    }
}
int main()
{
    n = read(), m = read();
    for(int i=1;i<n;++i) {
        int u = read(), v = read();
        add(u,v), add(v,u);
    }
    //cout << endl;
    Dfs(1,0); Init();
    qs[++qcnt] = 1;
    for(int i=1;i<=m;++i) {
        opt[i] = read(), X[i] = read();
        if(opt[i] == 2) {
            qt[qcnt] = i; qs[++qcnt] = i + 1;
        }
    }
    qt[qcnt] = m + 1;
    //cout << endl;
    //for(int i=1;i<=qcnt;++i) printf("%d %d
",qs[i],qt[i]);
    for(int i=1;i<=qcnt;++i) {
        int qn = qt[i] - qs[i];
        if(qn <= sqrt(m)) {
            //puts("test");
            Calc1(qs[i], qt[i]);
        } else {
            Calc2(qs[i], qt[i]);
        }
    }
    for(int i=0;i<ans.size();++i) {
        if(ans[i] == 1) puts("wrxcsd");
        else puts("orzFsYo");
    }
    return 0;
}
/*
5 4
1 2
1 3
2 4
2 5
1 2
3 2
2 4
3 4
 
wrxcsd
orzFsYo
*/
原文地址:https://www.cnblogs.com/BaseAI/p/13862340.html