1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxm = 1e5 + 5; 7 int n, m, ans; 8 pair<int, int> p[maxm]; 9 10 int main() { 11 ios_base::sync_with_stdio(0); 12 cin.tie(0); 13 14 cin >> n >> m; 15 for (int i = 1; i <= m; i++) { 16 cin >> p[i].first >> p[i].second; 17 } 18 p[++m] = {n + 1, n + 1}; 19 sort(p + 1, p + 1 + m); 20 for (int i = 1, last = 1, pos; i <= m; i = pos + 1){ 21 if (p[i].first > last) { 22 cout << -1 << endl; 23 return 0; 24 } 25 pos = i; 26 int tmp = p[pos].second; 27 while (pos < m && p[pos + 1].first <= last) { 28 tmp = max(tmp, p[++pos].second); 29 } 30 last = tmp + 1; 31 ans++; 32 if (last > n) break; 33 } 34 cout << ans << endl; 35 return 0; 36 }
1 #include <cstdio> 2 #include <cmath> 3 4 typedef long long ll; 5 int T; 6 ll a, b, p; 7 8 inline ll ksc(ll a, ll b, ll mod) { 9 return ((a * b - (ll)((long double)a / mod * b) * mod) % mod + mod) % mod; 10 } 11 12 inline ll ksm(ll a, ll b, ll p) { 13 ll res = 1ll; 14 for (; b; b >>= 1) { 15 if (b & 1) res = ksc(res, a, p); 16 a = ksc(a, a, p); 17 } 18 return res; 19 } 20 21 int main() { 22 for (scanf("%d", &T); T; T--) { 23 scanf("%lld %lld %lld", &a, &b, &p); 24 printf("%lld ", ksm(a % p, b, p)); 25 } 26 }
1 #include <cstdio> 2 3 typedef long long ll; 4 const int maxn = 13e6 + 5; 5 const int mod = 1e9 + 7; 6 int n, primes[maxn], tot, val[maxn]; 7 ll ans; 8 bool vis[maxn]; 9 10 int ksm(int a, int b) { 11 int res = 1ll; 12 for (; b; b >>= 1) { 13 if (b & 1) res = (ll)res * a % mod; 14 a = (ll)a * a % mod; 15 } 16 return res; 17 } 18 19 void pre(int n) { 20 val[1] = 1; 21 for (int i = 2; i <= n; i++) { 22 if (!vis[i]) { 23 val[i] = ksm(i, n); 24 primes[++tot] = i; 25 } 26 for (int j = 1; j <= tot && primes[j] * i <= n; j++) { 27 vis[primes[j] * i] = true; 28 val[primes[j] * i] = (ll)val[primes[j]] * val[i] % mod; 29 if (i % primes[j] == 0) break; 30 } 31 } 32 } 33 34 int main() { 35 scanf("%d", &n); 36 pre(n); 37 for (int i = 1; i <= n; i++) 38 ans = ans ^ val[i]; 39 printf("%lld ", ans); 40 return 0; 41 }
D题不会推式子嘤。反演什么的更不敢试了,欧拉累加能过就行了(逃
1 #include <cstdio> 2 #include <cstring> 3 #include <cctype> 4 5 template <typename T> void read(T &x) { 6 x = 0; 7 int s = 1, c = getchar(); 8 for (; !isdigit(c); c = getchar()) 9 if (c == '-') s = -1; 10 for (; isdigit(c); c = getchar()) 11 x = x * 10 + c - 48; 12 } 13 14 template <typename T> void write(T x) { 15 if (x < 0) x = -x, putchar('-'); 16 if (x > 9) write(x / 10); 17 putchar(x % 10 + '0'); 18 } 19 20 template <typename T> void writeln(T x) { 21 write(x); 22 puts(""); 23 } 24 25 const int maxn = 1e6 + 5; 26 int n; 27 int phi[maxn], primes[maxn], tot; 28 bool vis[maxn]; 29 long long val[maxn]; 30 31 void euler(int n) { 32 phi[1] = 1; 33 for (int i = 2; i <= n; i++) { 34 if (!vis[i]) { 35 primes[++tot] = i; 36 phi[i] = i - 1; 37 } 38 for (int j = 1; j <= tot && primes[j] * i <= n; j++) { 39 vis[primes[j] * i] = true; 40 phi[primes[j] * i] = phi[i] * (i % primes[j] ? primes[j] - 1 : primes[j]); 41 if (i % primes[j] == 0) break; 42 } 43 } 44 } 45 46 void solve() { 47 for (int d = 1; d <= n; d++) { 48 val[d]++; 49 for (int k = 2; k * d <= n; k++) { 50 val[k * d] += (long long)phi[k] * k / 2; 51 } 52 } 53 for (int i = 1; i <= n; i++) { 54 writeln(val[i]); 55 } 56 } 57 58 int main() { 59 read(n); 60 euler(n); 61 solve(); 62 return 0; 63 }
1 #include <cstdio> 2 3 const int maxn = 2e5 + 5; 4 int N, K, a[maxn]; 5 6 bool ok(int len) { 7 long long res = 0; 8 for (int i = 1; i <= N; i++) 9 res += a[i] / len; 10 return res >= K; 11 } 12 13 int main() { 14 scanf("%d %d", &N, &K); 15 for (int i = 1; i <= N; i++) 16 scanf("%d", &a[i]); 17 int l = 1, r = 1e9, ans; 18 while (l <= r) { 19 int mid = (l + r) >> 1; 20 if (ok(mid)) { 21 ans = mid; 22 l = mid + 1; 23 } else r = mid - 1; 24 } 25 printf("%d ", ans); 26 return 0; 27 }
F题说一说。
无脑树状数组显然会爆时间,命题人的方法是sqrt一个块作为界限,对于小复杂度的进行暴力插,大复杂度修改值的记录在桶里,然后每次询问时询问完树状数组再暴力扫一遍块里我们还应该加上的部分。温和地缓解了复杂度压力吧。
1 #include <cstdio> 2 #include <cctype> 3 #include <cmath> 4 5 typedef long long ll; 6 const int maxn = 1e5 + 5; 7 int N, M, T; 8 ll F[maxn], val[maxn]; 9 10 template <typename T> void read(T &x) { 11 x = 0; 12 int s = 1, c = getchar(); 13 for (; !isdigit(c); c = getchar()) 14 if (c == '-') s = -1; 15 for (; isdigit(c); c = getchar()) 16 x = x * 10 + c - 48; 17 x *= s; 18 } 19 20 template <typename T> void write(T x) { 21 if (x < 0) x = -x, putchar('-'); 22 if (x > 9) write(x / 10); 23 putchar(x % 10 + '0'); 24 } 25 26 template <typename T> void writeln(T x) { 27 write(x); 28 puts(""); 29 } 30 31 void Add(int x, int val) { 32 for (; x <= N; x += x&-x) 33 F[x] += val; 34 } 35 36 ll Query(int x) { 37 ll ret = 0; 38 for (; x; x -= x&-x) 39 ret += F[x]; 40 return ret; 41 } 42 43 ll cal(int n) { 44 ll ret = Query(n); 45 for (int i = 1; i <= T; i++) { 46 ret += val[i] * (n / i); 47 } 48 return ret; 49 } 50 51 int main() { 52 read(N), read(M); 53 for (T = sqrt(N); M; M--) { 54 int op, a, b; 55 read(op), read(a), read(b); 56 if (op == 1) { 57 if (a > T) { 58 for (int i = a; i <= N; i += a) 59 Add(i, b); 60 } else { 61 val[a] += b; 62 } 63 } else { 64 writeln(cal(b) - cal(a - 1)); 65 } 66 } 67 return 0; 68 }
我又试了试,验题人的做法,然后最后一个点T了……也贴这吧。思路是树状数组只修改这个数字D,不用修改D的倍数,然后询问时用整除分块+树状数组查询前缀和的方式。
update:验题人本人代码也被T了233……
1 #include <cstdio> 2 3 typedef long long ll; 4 const int maxn = 1e5 + 5; 5 int N, M; 6 ll F[maxn]; 7 8 void Add(int x, int val) { 9 for (; x <= N; x += x&-x) 10 F[x] += val; 11 } 12 13 ll Query(int x) { 14 ll ret = 0; 15 for (; x; x -= x&-x) 16 ret += F[x]; 17 return ret; 18 } 19 20 ll cal(int n) { 21 ll ret = 0; 22 for (int l = 1, r; l <= n; l = r + 1) { 23 r = n / (n / l); 24 ret += (Query(r) - Query(l - 1)) * (n / l); 25 } 26 return ret; 27 } 28 29 int main() { 30 for (scanf("%d %d", &N, &M); M; M--) { 31 int op, a, b; 32 scanf("%d %d %d", &op, &a, &b); 33 if (op == 1) { 34 Add(a, b); 35 } else { 36 printf("%lld ", cal(b) - cal(a - 1)); 37 } 38 } 39 return 0; 40 }
1 #include <cstdio> 2 #include <algorithm> 3 4 long long a, b; 5 char s[100005]; 6 7 int main() { 8 scanf("%lld %lld %s", &a, &b, s); 9 printf("%lld ", std::__gcd(a, b)); 10 }
H题说一说。
对所有的子树加操作,考虑树剖。把树建成以后dfs序一下进行转换会使得父子兄弟节点都挨着,这样就好维护了。(树剖是用线段树,本题官解用的差分树状数组。)
离线。之后重读一遍M个操作,如果是操作一,那这个点是新建的,则把它一个人的值清零(操作二会导致之前它还没出现但是却有值);
如果是操作二,则把这个点加个值,因为树状数组维护了前缀和,所以如果查询的话其实他(dfs序)之后的点也加了值,所以差分一下,在孩子以后的点再减去这个不应属于它们的值;
操作三询问,直接询问前缀和即可。因为我们差分了,所以这个查询只会包含它本身及其各位祖先节点加过的值,正是所需。
1 #include <cstdio> 2 #include <cctype> 3 #include <vector> 4 using namespace std; 5 6 template <typename T> void read(T &x) { 7 x = 0; 8 int s = 1, c = getchar(); 9 for (; !isdigit(c); c = getchar()) 10 if (c == '-') s = -1; 11 for (; isdigit(c); c = getchar()) 12 x = x * 10 + c - 48; 13 x *= s; 14 } 15 16 template <typename T> void write(T x) { 17 if (x < 0) x = -x, putchar('-'); 18 if (x > 9) write(x / 10); 19 putchar(x % 10 + '0'); 20 } 21 22 template <typename T> void writeln(T x) { 23 write(x); 24 puts(""); 25 } 26 27 const int maxn = 1e5 + 5, maxm = 4e5 + 5; 28 int M, tot, time, DFN[maxn], SIZE[maxn]; 29 vector<int> v[maxn]; 30 31 struct Operation { 32 int op, i, a; 33 }OP[maxm]; 34 35 struct BIT { 36 int F[maxn]; 37 38 void Update(int pos, int val) { 39 for (; pos <= time; pos += pos&-pos) 40 F[pos] += val; 41 } 42 43 void Add(int l, int r, int val) { 44 Update(l, val); 45 Update(r, -val); 46 } 47 48 int Query(int pos) { 49 int ret = 0; 50 for (; pos; pos -= pos&-pos) 51 ret += F[pos]; 52 return ret; 53 } 54 }T; 55 56 void dfs(int cur) { 57 DFN[cur] = ++time; 58 SIZE[cur] = 1; 59 for (auto son : v[cur]) { 60 dfs(son); 61 SIZE[cur] += SIZE[son]; 62 } 63 } 64 65 int main() { 66 read(M); 67 for (int i = 1; i <= M; i++) { 68 read(OP[i].op), read(OP[i].i); 69 if (OP[i].op == 1) { 70 v[OP[i].i].push_back(++tot); 71 } else if (OP[i].op == 2) { 72 read(OP[i].a); 73 } 74 } 75 dfs(0); 76 tot = 0; 77 for (int i = 1; i <= M; i++) { 78 if (OP[i].op == 1) { 79 ++tot; 80 T.Add(DFN[tot], DFN[tot] + 1, -T.Query(DFN[tot])); 81 } else if (OP[i].op == 2) { 82 int curnode = OP[i].i; 83 T.Add(DFN[curnode], DFN[curnode] + SIZE[curnode], OP[i].a); 84 } else { 85 writeln(T.Query(DFN[OP[i].i])); 86 } 87 } 88 return 0; 89 }
1 #include <cstdio> 2 #define min(a, b) a < b ? a : b 3 4 const int maxn = 1e5 + 5; 5 const int maxm = 6e5 + 5; 6 int N, M, tot, time, ans; 7 int head[maxn], DFN[maxn], low[maxn]; 8 bool vis[maxn]; 9 struct EDGE { 10 int to, nxt; 11 }e[maxm]; 12 13 void add(int u, int v) { 14 e[++tot].to = v; 15 e[tot].nxt = head[u]; 16 head[u] = tot; 17 } 18 19 void dfs(int cur, int fa) { 20 DFN[cur] = low[cur] = ++time; 21 vis[cur] = true; 22 for (int i = head[cur]; i; i = e[i].nxt) { 23 int son = e[i].to; 24 if (!vis[son]) { 25 dfs(son, cur); 26 low[cur] = min(low[cur], low[son]); 27 if (low[son] > DFN[cur]) 28 ans++; 29 } else if (son != fa) { 30 low[cur] = min(low[cur], DFN[son]); 31 } 32 } 33 } 34 35 int main() { 36 scanf("%d %d", &N, &M); 37 for (int i = 1; i <= M; i++) { 38 int u, v; 39 scanf("%d %d", &u, &v); 40 add(u, v); 41 add(v, u); 42 } 43 dfs(1, 0); 44 printf("%d ", M - ans); 45 return 0; 46 }
J题说一说。
既然只有26个字母,考虑往这上转化。做法是:因为只是子序列就行,所以贪心选取,优先选取前面的位置。O(26*len)的复杂度预处理一个叫“序列自动机”的东西,得出“对于位置i,下一个字母j最早出现在哪个位置”。这样之后每个询问的串,只要跟着自动机跳就行了,复杂度都是O(m)的。
1 #include <cstdio> 2 #include <cstring> 3 4 const int maxn = 1e6 + 5; 5 int n, len; 6 int Go[maxn][27]; 7 char str[maxn]; 8 char t[maxn]; 9 10 int main() { 11 scanf("%s", str + 1); 12 len = strlen(str + 1); 13 for (int i = len - 1; ~i; --i) { 14 for (int j = 1; j <= 26; ++j) { 15 Go[i][j] = Go[i + 1][j]; 16 } 17 Go[i][str[i + 1] - 'a' + 1] = i + 1; 18 } 19 for (scanf("%d", &n); n; n--) { 20 scanf("%s", t); 21 bool flag = true; 22 for (int i = 0, j = 0; t[i]; ++i) { 23 if (Go[j][t[i] - 'a' + 1]) { 24 j = Go[j][t[i] - 'a' + 1]; 25 } else { 26 flag = false; 27 break; 28 } 29 } 30 flag ? puts("Yes") : puts("No"); 31 } 32 return 0; 33 }