题目## 题目## 题目## 题目
解题思路
- 首先需要理解"素数伴侣"的概念:两个数的和为素数
- 这是一个最大二分图匹配问题:
- 将偶数和奇数分成两组
- 如果一个奇数和一个偶数之和是素数,则它们之间有一条边
- 使用匈牙利算法求解最大匹配:
- 对于每个奇数,尝试为其匹配一个偶数
- 如果当前偶数已被匹配,尝试为原配找新的匹配
代码
def is_prime(n):
"""判断一个数是否为素数"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
def find(x, used, match, evens, odds):
"""匈牙利算法的查找函数"""
for i, even in enumerate(evens):
# 如果和为素数且未使用过
if is_prime(even + odds[x]) and not used[i]:
used[i] = True
# 如果当前偶数未匹配或者它的匹配可以找到新的配对
if match[i] == -1 or find(match[i], used, match, evens, odds):
match[i] = x
return True
return False
while True:
try:
# 读取输入
n = int(input())
nums = list(map(int, input().split()))
# 分离奇数和偶数
odds = [x for x in nums if x % 2 == 1]
evens = [x for x in nums if x % 2 == 0]
# 初始化匹配数组
match = [-1] * len(evens)
count = 0
# 对每个奇数尝试匹配
for i in range(len(odds)):
used = [False] * len(evens)
if find(i, used, match, evens, odds):
count += 1
print(count)
except EOFError:
break
#include <iostream>
#include <vector>
using namespace std;
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
bool find(int x, vector<bool>& used, vector<int>& match,
const vector<int>& evens, const vector<int>& odds) {
for (int i = 0; i < evens.size(); i++) {
if (isPrime(evens[i] + odds[x]) && !used[i]) {
used[i] = true;
if (match[i] == -1 || find(match[i], used, match, evens, odds)) {
match[i] = x;
return true;
}
}
}
return false;
}
int main() {
int n;
while (cin >> n) {
vector<int> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
// 分离奇数和偶数
vector<int> odds, evens;
for (int num : nums) {
if (num % 2) odds.push_back(num);
else evens.push_back(num);
}
// 匈牙利算法求最大匹配
vector<int> match(evens.size(), -1);
int count = 0;
for (int i = 0; i < odds.size(); i++) {
vector<bool> used(evens.size(), false);
if (find(i, used, match, evens, odds)) {
count++;
}
}
cout << count << endl;
}
return 0;
}
import java.util.*;
public class Main {
private static boolean isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
private static boolean find(int x, boolean[] used, int[] match,
List<Integer> evens, List<Integer> odds) {
for (int i = 0; i < evens.size(); i++) {
if (isPrime(evens.get(i) + odds.get(x)) && !used[i]) {
used[i] = true;
if (match[i] == -1 || find(match[i], used, match, evens, odds)) {
match[i] = x;
return true;
}
}
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
List<Integer> odds = new ArrayList<>();
List<Integer> evens = new ArrayList<>();
// 分离奇数和偶数
for (int i = 0; i < n; i++) {
int num = sc.nextInt();
if (num % 2 == 1) odds.add(num);
else evens.add(num);
}
// 匈牙利算法求最大匹配
int[] match = new int[evens.size()];
Arrays.fill(match, -1);
int count = 0;
for (int i = 0; i < odds.size(); i++) {
boolean[] used = new boolean[evens.size()];
if (find(i, used, match, evens, odds)) {
count++;
}
}
System.out.println(count);
}
}
}
算法及复杂度
- 算法:匈牙利算法(最大二分图匹配)
- 时间复杂度: O ( V E ) \mathcal{O}(VE) O(VE),其中V是顶点数(数字个数),E是边数(可能的素数伴侣对数)
- 空间复杂度: O ( V ) \mathcal{O}(V) O(V),用于存储匹配状态和访问标记
解题思路
-
记录处理:
- 分割每行记录,获取文件路径和行号
- 从文件路径中提取文件名(最后一个反斜杠后的部分)
- 如果文件名超过16个字符,只保留最后16个字符
-
错误统计:
- 使用字典存储错误记录,键为(文件名,行号)的元组
- 每次遇到相同的错误记录,计数加1
-
结果输出:
- 按照记录出现的顺序输出最后8条记录
- 每条记录包含:文件名 行号 出现次数
代码
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
pair<string, string> getFilenameAndLine(const string& record) {
// 查找最后一个反斜杠位置
size_t lastSlash = record.find_last_of('\\');
if (lastSlash == string::npos) return {"", ""};
// 查找行号(空格后的部分)
size_t spacePos = record.find(' ', lastSlash);
if (spacePos == string::npos) return {"", ""};
// 提取文件名和行号
string filename = record.substr(lastSlash + 1, spacePos - lastSlash - 1);
string lineNumber = record.substr(spacePos + 1);
// 如果文件名超过16个字符,只保留最后16个
if (filename.length() > 16) {
filename = filename.substr(filename.length() - 16);
}
return {filename, lineNumber};
}
int main() {
string record;
vector<pair<string, string>> records; // 存储所有记录
map<pair<string, string>, int> errorRecords; // 统计每条记录的出现次数
// 读取记录
while (getline(cin, record)) {
auto [filename, lineNumber] = getFilenameAndLine(record);
if (filename.empty()) continue;
pair<string, string> key = {filename, lineNumber};
if (errorRecords.find(key) == errorRecords.end()) {
records.push_back(key); // 只在第一次出现时添加到records
}
errorRecords[key]++;
}
// 输出最后8条记录
size_t start = records.size() > 8 ? records.size() - 8 : 0;
for (size_t i = start; i < records.size(); i++) {
const auto& record = records[i];
cout << record.first << " "
<< record.second << " "
<< errorRecords[record] << endl;
}
return 0;
}
import java.util.*;
public class Main {
static class Record {
String filename;
String lineNumber;
Record(String filename, String lineNumber) {
this.filename = filename;
this.lineNumber = lineNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Record record = (Record) o;
return Objects.equals(filename, record.filename) &&
Objects.equals(lineNumber, record.lineNumber);
}
@Override
public int hashCode() {
return Objects.hash(filename, lineNumber);
}
}
private static Record getFilenameAndLine(String record) {
// 查找最后一个反斜杠位置
int lastSlash = record.lastIndexOf('\\');
if (lastSlash == -1) return null;
// 查找行号(空格后的部分)
int spacePos = record.indexOf(' ', lastSlash);
if (spacePos == -1) return null;
// 提取文件名和行号
String filename = record.substring(lastSlash + 1, spacePos);
String lineNumber = record.substring(spacePos + 1);
// 如果文件名超过16个字符,只保留最后16个
if (filename.length() > 16) {
filename = filename.substring(filename.length() - 16);
}
return new Record(filename, lineNumber);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Map<Record, Integer> errorRecords = new LinkedHashMap<>();
// 读取记录
while (sc.hasNextLine()) {
String line = sc.nextLine();
if (line.isEmpty()) break;
Record record = getFilenameAndLine(line);
if (record == null) continue;
errorRecords.put(record, errorRecords.getOrDefault(record, 0) + 1);
}
// 输出最后8条记录
List<Map.Entry<Record, Integer>> records = new ArrayList<>(errorRecords.entrySet());
int start = Math.max(0, records.size() - 8);
for (int i = start; i < records.size(); i++) {
Map.Entry<Record, Integer> entry = records.get(i);
System.out.println(entry.getKey().filename + " " +
entry.getKey().lineNumber + " " +
entry.getValue());
}
sc.close();
}
}
def get_filename_and_line(record):
# 分割路径和行号
parts = record.strip().split()
if len(parts) != 2:
return None, None
path, line_number = parts
# 获取文件名(取路径最后一个反斜杠后的部分)
filename = path.split('\\')[-1]
# 如果文件名超过16个字符,只保留最后16个
if len(filename) > 16:
filename = filename[-16:]
return filename, line_number
def main():
# 使用字典记录错误出现次数
error_records = {}
while True:
try:
record = input()
if not record:
break
filename, line_number = get_filename_and_line(record)
if filename is None:
continue
# 使用文件名和行号作为键
key = (filename, line_number)
error_records[key] = error_records.get(key, 0) + 1
except EOFError:
break
# 输出最后8条记录
for (filename, line_number), count in list(error_records.items())[-8:]:
print(f"{filename} {line_number} {count}")
if __name__ == "__main__":
main()
算法及复杂度
- 算法:哈希表统计
- 时间复杂度: O ( n ) \mathcal{O}(n) O(n),其中n是输入记录的数量
- 空间复杂度: O ( n ) \mathcal{O}(n) O(n),需要存储所有不重复的错误记录
解题思路
这是一个等差数列求和问题。给定一个从2开始、公差为3的等差数列,需要求出前n项的和。
关键点
-
数据范围: 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1≤n≤1000
-
等差数列特点:
- 首项 a 1 = 2 a_1 = 2 a1=2
- 公差 d = 3 d = 3 d=3
- 第n项通项公式: a n = a 1 + ( n − 1 ) d = 2 + 3 ( n − 1 ) a_n = a_1 + (n-1)d = 2 + 3(n-1) an=a1+(n−1)d=2+3(n−1)
-
求和方法:
- 使用等差数列求和公式: S n = n ( a 1 + a n ) / 2 S_n = n(a_1 + a_n)/2 Sn=n(a1+an)/2
- 或者: S n = n [ 2 a 1 + ( n − 1 ) d ] / 2 S_n = n[2a_1 + (n-1)d]/2 Sn=n[2a1+(n−1)d]/2
代码
#include <iostream>
using namespace std;
int main() {
int n;
while (cin >> n) {
// 使用等差数列求和公式
// 首项a₁ = 2,公差d = 3
// 第n项 aₙ = 2 + (n-1)*3
// 和 Sₙ = n(a₁ + aₙ)/2
long long sum = (long long)n * (4 + (n-1)*3) / 2;
cout << sum << endl;
}
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
// 使用等差数列求和公式
// 首项a₁ = 2,公差d = 3
// 第n项 aₙ = 2 + (n-1)*3
// 和 Sₙ = n(a₁ + aₙ)/2
long sum = (long)n * (4 + (n-1)*3) / 2;
System.out.println(sum);
}
}
}
while True:
try:
n = int(input())
# 使用等差数列求和公式
# 首项a₁ = 2,公差d = 3
# 第n项 aₙ = 2 + (n-1)*3
# 和 Sₙ = n(a₁ + aₙ)/2
sum = n * (4 + (n-1)*3) // 2
print(sum)
except:
break
算法及复杂度
算法分析
-
计算过程:
- 使用等差数列求和公式直接计算
- 避免使用循环累加,提高效率
- 注意使用长整型避免溢出
-
公式推导:
- 首项 a 1 = 2 a_1 = 2 a1=2
- 公差 d = 3 d = 3 d=3
- 第n项 a n = 2 + ( n − 1 ) ∗ 3 a_n = 2 + (n-1)*3 an=2+(n−1)∗3
- 求和公式 S n = n ( a 1 + a n ) / 2 S_n = n(a_1 + a_n)/2 Sn=n(a1+an)/2
- 代入得: S n = n [ 4 + ( n − 1 ) ∗ 3 ] / 2 S_n = n[4 + (n-1)*3]/2 Sn=n[4+(n−1)∗3]/2
复杂度分析
- 时间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 使用公式直接计算,不需要循环
- 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要常数级的额外空间
bitset 模拟 01背包。
#include <iostream>
#include <bitset>
using namespace std;
const int N=200100;
const int M=20;
bitset<N> b;
int m[M],x[M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,i,j;
cin>>n;
for(i=1;i<=n;++i)
cin>>m[i];
for(i=1;i<=n;++i)
cin>>x[i];
b[0]=1;
for(i=1;i<=n;++i)
for(j=1;j<=x[i];++j)
b|=b<<m[i];
cout<<b.count();
return 0;
}
514

被折叠的 条评论
为什么被折叠?



