牛客小白月赛12

比赛传送门

这真的是小白月赛么……
说好的“题目难度在\(CF\; DIV2\;A\)~\(C\)”呢?
\(D,E\)两题为数学题,所以不想整(并没有歧视数学的意思)

A.华华听月月唱歌

贪心区间覆盖裸题,但细节需要注意

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { 
        if(c == '-') f = -1;
        c = getchar(); 
    } 
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
struct zzz {
	int f, t;
}xd[100010];
bool cmp(zzz x, zzz y) {
    if(x.f != y.f)  return x.f < y.f;
    else return x.t > y.t;
}
int main() {
    int n = read(), tot = read();
	for(int i = 1; i <= tot; ++i)
	  xd[i].f = read(), xd[i].t = read();
    sort(xd+1, xd+tot+1, cmp);
	int t = 0, ans = 0, pos = 1;
	while(t < n) {
		++ans;
		int flag = t;
		for(; xd[pos].f <= flag+1 && pos <= tot; ++pos)
		  t = max(t, xd[pos].t);
		if(t == flag && flag < n) {
			cout << -1; exit(0);
		}
	}
	cout << ans;
	return 0;
}

B.华华教月月做数学

快速幂+龟速乘

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
LL mul(LL b, LL p, LL k) {
    LL ans = 0;
    for(; p; p >>= 1) {
        if(p & 1)
          ans = (ans + b) % k;
        b = (b + b) % k;
    }
    return ans % k;
}
LL pow(LL b, LL p, LL k) {
    LL ans = 1;
    for(; p; p >>= 1) {
        if(p & 1)
          ans = mul(ans, b, k);
        b = mul(b, b, k);
    }
    return ans % k;
}
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
int main() {
    int t = read();
    while(t--) {
        LL b = read(), p = read(), k = read();
        cout << pow(b, p, k) << endl;
    }
    return 0;
}

还有好写的Python

t = input()
for i in range(0, (int)(t)) :
	s = input().split()
	print(pow(int(s[0]), int(s[1]) , int(s[2])))

E.华华给月月准备礼物

二分答案

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { 
        if(c == '-') f = -1;
        c = getchar(); 
    } 
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
int a[200010], l = 1, r;
int n, m;
bool judge(int x) {
	int ans = 0;
	for(int i = 1; i <= n; ++i)
	  ans += a[i]/x;
	if(ans < m) return 0;
	else return 1;
}
int main() {
    n = read(), m = read();
	for(int i = 1; i <= n; ++i)
	  a[i] = read(), r = max(a[i], r)+1;
	while(l < r) {
		int mid = (l+r) >> 1;
		if(judge(mid)) l = mid+1;
		else r = mid;
	}
	cout << l-1;
	return 0;
}

F.华华开始学信息学

很神仙的一道题,之前从来没见过这种思想

如果暴力使用树状数组来维护,每次修改的时间复杂度为\(O(\frac{n}{x}\log n)\)\(x\)为模数,查询时间复杂度为\(O(n \log n)\)

显然可以发现当\(x\)越大,使用树状数组维护的效率越高,而\(x\)较小的时候使用树状数组是十分不理智的,此时可以使用一个桶来维护,令tong[i]表示模数为\(i\)时加了多少

\(x\)为多少时用树状数组或是桶呢?
显然当\(x\)\(\sqrt{n}\)时效率最高,修改时为\(O(\sqrt{n} \log n)\),查询为\(O(\sqrt{n}+ \log n)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define LL long long
#define lb (i & (-i))
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
LL tree[100010 << 1], tong[100010];
int n, m;
void add(int pos, LL x) {
    for(int i = pos; i <= n; i += lb) tree[i] += x;
}
LL sum(int pos) {
    LL ans = 0;
    for(int i = pos; i; i -= lb) ans += tree[i];
    return ans;
}
int main() {
    n = read(), m = read(); int maxx = sqrt(n);
    for(int i = 1; i <= m; ++i) {
        LL opt = read(), x = read(), y = read();
        if(opt == 1) {
            if(x > maxx)
              for(int j = x; j <= n; j += x) add(j, y);
            else tong[x] += y;
        }
        else {
            LL ans = sum(y) - sum(x-1);
            for(int j = 1; j <= maxx; ++j) ans += (y/j - (x-1)/j) * tong[j];
            printf("%lld\n", ans);
        }
    }
    return 0;
}

G.华华对月月的忠诚

虽然\(N\)很大,但答案和\(N\)没有关系,直接求\(a,b\)\(gcd\)即可

H.华华和月月种树

一开始以为是树剖,事实证明我想多了(数据结构的受害者)

动态开点不好维护,我们可以离线操作
先在输入的时候跟着\(1\)操作加点,建出最终的树,然后求此树的\(DFS\)序和每个点的子树大小
这样就把\(2,3\)操作变为了区间加和单点查询,可以用查分树状数组来维护
而对于\(1\)操作,加入新的点时要将这个点上的信息清空

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define lb (i & (-i))
#define LL long long
using namespace std;
int read() {
	int k = 0; char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9')
	  k = k * 10 + c - 48, c = getchar();
	return k;
}
struct zzz {
	int t, nex;
}e[100010 << 1]; int head[100010], tot;
void add(int x, int y) {
	e[++tot].t = y;
	e[tot].nex = head[x];
	head[x] = tot;
}
struct hhh {
	int opt, x, y;
}que[400010]; int cnt;
int siz[100010], p[100010], num = 1;
void dfs(int pos, int fa) {
	p[pos] = num;
	for(int i = head[pos]; i; i = e[i].nex)
	  if(e[i].t != fa)
		++num, dfs(e[i].t, pos), siz[pos] += siz[e[i].t];
	siz[pos] += 1;
}
int m, n;
LL tree[100010 << 1];
void del(int x) {
	for(int i = x; i <= n; i += lb) tree[i] = 0;
}
void update(int x, int k) {
	for(int i = x; i <= n; i += lb) tree[i] += k;
}
LL sum(int x) {
	LL ans = 0;
	for(int i = x; i; i -= lb) ans += tree[i];
	return ans;
}
int main() {
	m = read(), n = 1;
	for(int i = 1; i <= m; ++i) {
		int x = read(); que[++cnt].opt = x;
		if(x == 1) {
			int y = read()+1; que[cnt].x = y;
			add(++n, y), add(y, n);
		}
		if(x == 2)
		  que[cnt].x = read()+1, que[cnt].y = read();
		if(x == 3)
		  que[cnt].x = read()+1;
	}
	dfs(1, 0); num = 1;	
	for(int i = 1; i <= cnt; ++i) {
		if(que[i].opt == 1) {
			int pos = p[++num];
			int k = sum(pos); update(pos, -k), update(pos+1, k);
		}
		if(que[i].opt == 2) {
			int pos = que[i].x, k = que[i].y;
			update(p[pos], k); update(p[pos]+siz[pos], -k);
		}
		if(que[i].opt == 3) {
			int pos = que[i].x;
			printf("%lld\n", sum(p[pos]));
		}
	}
	return 0;
}

I.华华和月月逛公园

\(Tarjan\)求割边板子题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct zzz {
	int t, nex;
}e[300010 << 1];
int head[100010], tot;
void add(int x, int y) {
	e[++tot].t = y;
	e[tot].nex = head[x];
	head[x] = tot;
}
int dfn[100010], low[100010], deth, ans;
void tarjan(int pos, int fa) {
	low[pos] = dfn[pos] = ++deth;
	for(int i = head[pos]; i; i = e[i].nex) {
		int to = e[i].t;
		if(!dfn[to]) {
			tarjan(to, pos);
			low[pos] = min(low[pos], low[to]);
			if(low[to] > dfn[pos]) ++ans;
		}
		else if(to != fa)
		  low[pos] = min(low[pos], dfn[to]);
	}
}
int read() {
	int k = 0; char c = getchar();
	for (; c < '0' || c > '9';) c = getchar();
	for (; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - 48;
	return k;
}
int main() {
	int n = read(), m = read();
	for(int i = 1; i <= m; ++i) {
		int x = read(), y = read();
		add(x, y), add(y, x);
	}
	for(int i = 1; i <= n; ++i)
	  if(!dfn[i]) tarjan(i, i);
	cout << m - ans;
	return 0;
}

J.月月查华华的手机

学了一个新东西:“序列自动机”
对于母串每一位都记一下下一次出现某个字符的位置。匹配的时候从第零位(虚根)开始,如果能一直匹配下去就是\(Yes\),否则就是\(No\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define LL long long
#define lb (i & (-i))
using namespace std;
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
      k = k * 10 + c - 48, c = getchar();
    return k * f;
}
int e[1000010][26];
char A[1000010];
int main() {
	scanf("%s", A+1); int len = strlen(A+1);
	for(int i = len-1; i >= 0; --i) {
		for(int j = 0; j < 26; ++j) e[i][j] = e[i+1][j];
		e[i][A[i+1]-'a'] = i+1;
	}
	int m = read();
    for(int i = 1; i <= m; ++i) {
		scanf("%s", A+1);
		int nex = 0, pos = 1, len = strlen(A+1);
		while(e[nex][A[pos]-'a'] && pos <= len+1)
		  nex = e[nex][A[pos]-'a'], ++pos;
		if(pos <= len) printf("No\n");
		else printf("Yes\n");
	}

    return 0;
}
posted @ 2019-11-14 10:22  MorsLin  阅读(140)  评论(0编辑  收藏  举报