Practice.
A. Polycarp and the Day of Pi
题意
将输入与 “
思路
模拟即可。
时间复杂度:
对应AC代码
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while (t-- > 0) {
String a = "314159265358979323846264338327";
String b = scanner.next();
int n = b.length(), cnt = 0;
for(int i=0;i<n;i++){
if(a.charAt(i) != b.charAt(i)) break;
cnt ++;
}
System.out.println(cnt);
}
}
}
题例有给圆周率的值,草
B. Taisia and Dice
题意
给定
思路
从大到小放入能放的最大数即可,上限需要考虑后面是否可以放
时间复杂度:
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t, n;
cin >> t;
while(t --){
int s, r;
cin >> n >> s >> r;
int maxx = s - r;
cout << maxx << ' ';
s -= maxx;
for(int i=n-2;i>=0;i--){
int cur = min(6ll, max(1ll, min(maxx, s - i)));
cout << cur << ' ';
s -= cur;
}
cout << '\n';
}
}
反正别用DFS就行
C. Premutation
题意
给定
思路
考虑第一位即可。
第一位中出现次数最多的数即为原排列的第一个数,而出现最少的数所在子序列即为原排列去掉第一个数后的子序列,拼起来即可。
时间复杂度:
对应AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N][N];
#define int long long
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t, n;
cin >> t;
while(t --) {
memset(a, 0, sizeof a);
cin >> n;
int h1, h2, c1 = 0, c2 = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - 1; j++) {
cin >> a[i][j];
}
if(c1 == 0 || h1 == a[i][0]) h1 = a[i][0], c1 ++;
else h2 = a[i][0], c2 ++;
}
int h = c1 > c2 ? h1 : h2;
for(int i=0;i<n;i++){
if(a[i][0] != h){
cout << h << ' ';
for(int j=0;j<n-1;j++) cout << a[i][j] << ' ';
break;
}
}
cout << '\n';
}
}
找规律就行力
D. Matryoshkas
题意
给定一个数组
思路
我们可以考虑模拟的做法,将所有子序列抽象为序列中最大的数,作为几堆候选区域:
在升序排序数组
- 如果满足
后和 相同,那么我们直接将元素放入该候选区域; - 如果两数相同,那么两数均可作为下一个数的可能候选区域,所以新建一个区域并放入该数;
- 否则,那么这个候选区域无法再进行匹配,直接取出并计数。
最后,剩下的堆数加上被取出的堆数即为答案。
当然,为了降低复杂度,考虑使用优先队列。
时间复杂度:
对应AC代码
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while (t-- > 0) {
int n = scanner.nextInt();
int[] a = new int[n];
PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingInt(o -> o));
for(int i=0;i<n;i++) a[i] = scanner.nextInt();
Arrays.sort(a);
int cnt = 0;
for(int i=0;i<n;i++){
boolean ok = false;
while(!q.isEmpty()){
int now = q.poll();
if(now + 1 == a[i]) {
q.offer(a[i]);
ok = true;
break;
}else if(now == a[i]){
q.offer(a[i]);
q.offer(a[i]);
ok = true;
break;
}
else cnt ++;
}
if(!ok) q.offer(a[i]);
}
System.out.println(cnt + q.size());
}
}
}
其实可以不用这么模拟,太模拟了((
E. Vlad and a Pair of Numbers
题意
给定一个整数
思路
我们先来考虑
对于任意二进制数
而对于
我们注意到有除
考虑到对于二进制运算,
而显而易见,当
时间复杂度:
对应AC代码
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
nxt:
while (t-- > 0) {
int n = scanner.nextInt(); //有连着的1就不行
if(n % 2 == 1){
System.out.println(-1);
continue nxt;
}
int a = 0, b = 0;
boolean f = false;
for(char e : Integer.toBinaryString(n).toCharArray()){
int p = e - '0';
if (f) {
if (p == 1) {
System.out.println(-1);
continue nxt;
} else {
a = a * 2 + 1;
b = b * 2 + 1;
f = false;
}
} else {
f = p == 1;
a *= 2;
b *= 2;
if(f) a ++;
}
}
System.out.printf("%d %d\n", a, b);
}
}
}
真的不是找规律题么((
F. Timofey and Black-White Tree
题意
对于一个
思路
我们可以考虑树形
难道我们要把子节点全都遍历一遍吗?显然不用。
这是一个无向无环图,那么显然一个点只有一个父节点,只要根节点确定了,我们构建一个数组即可。
因此,我们不妨从要涂色的点开始,向上
深搜剪枝
- 根节点的确定:在绝大多数情况下,取子节点最多的点作为根节点是更优的,这样可以让链条结构更多,从而一定程度降低时间复杂度;
- 只遍历父节点
时,结束遍历:显然,我们需要求答案的最小值,那么就算我们继续遍历,最后更新的 值是一定大于等于 的,因而我们就没必要 让其他将要涂黑的点 以这个点为跳板 来更新 了。而恰恰因为我们至少遍历了 个,可以保证 最小路径所在边 一定被我们遍历过了,因而答案没有问题。
整体来看
- 确定根节点;
- 从根节点开始向下
一遍,求出每个点的父节点; - 依次遍历要涂黑的点,向上
并更新 值。
时间复杂度:不会分析
对应AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200010, inf = 0x3f3f3f3f;
#define int long long
vector<int> e[N];
int dp[N], c[N], root, ans, vis[N], f[N];//cut2: 只遍历爹,因为爹只有一个(无环
void dfs1(int fa){
for(int p : e[fa]){
if(vis[p]) continue;
vis[p] = true;
f[p] = fa;
dfs1(p);
}
}
void dfs2(int child, int st){
if(st >= ans) return; //cut3: 步数那么多就没必要继续走,防止每次都被卡O(n)
if(dp[child] != inf) ans = min(ans, dp[child] + st);
dp[child] = min(st, dp[child]);
if(child != root) dfs2(f[child], st + 1);
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t, n;
cin >> t;
while(t --) {
cin >> n >> c[0];
for(int i=1;i<n;i++) {
cin >> c[i];
dp[i] = inf;
vis[i] = false;
e[i].clear();
}
dp[n] = inf;
vis[n] = false;
e[n].clear();
int maxx = -1;
root = 1; //cut1: 根节点选分支最多的
for(int i=1;i<n;i++){
int u, v;
cin >> u >> v;
e[u].emplace_back(v);
e[v].emplace_back(u);
int s1 = e[u].size(), s2 = e[v].size();
if(max(s1, s2) > maxx) {
maxx = max(s1, s2);
root = s1 > s2 ? u : v;
}
}
dfs1(root);
ans = inf;
dfs2(c[0], 0);
for(int i=1;i<n;i++){
dfs2(c[i], 0);
cout << ans << ' ';
}
cout << '\n';
}
}
我趣,怎么一遍过
- 本文链接 https://floating-ocean.github.io/blog_old/posts/3800321871/
- 版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!