ECNU OJ重点题目汇总,供自己复习
一、 常用算法
1. 素数,筛选法
int num[20010];
void prime() {
num[1] = 1;
for (int i = 2; i < 20010; i++) {
if (num[i] == 0) {
num[i] = 1;
for (int j = i * i; j < 20010; j+=i) {
num[j] = -1;
}
}
}
}
2. 最大公约数,辗转相除法
//方法一
int gcd(int n,int m){
if(n % m == 0){
return m;
}
return gcd(m,n%m);
}
//方法二,方法一的简化版
int gcd(int n, int m) {
return m ? gcd(m, n % m) : n;
}
//求多个数的最大公约数
int gcds(int arr[], int m) {
int tem = arr[0];
for (int i = 1; i < m; i++) {
tem = gcd(tem,arr[i]);//这里的gcd函数与上文辗转相除一致
}
return tem;
}
最小公倍数
int lcm(int a,int b){
return a*b/gcd(a,b);
}
3. 最大公共子序列
无需连续
class Solution {
public:
/**
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
string LCS(string s1, string s2) {
int m = s1.length(),n = s2.length();
if(m==0 || n==0)
return "-1";
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
vector<vector<char>> turn(m,vector<char>(n,0));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(s1[i]==s2[j])
dp[i+1][j+1] = dp[i][j] + 1;
else
if(dp[i][j+1]>dp[i+1][j])
dp[i+1][j+1] = dp[i][j+1], turn[i][j]='U';
else
dp[i+1][j+1] = dp[i+1][j], turn[i][j]='L';
}
}
if(dp[m][n]==0)
return "-1";
string ans;
// search
for(int i = m-1, j = n-1;i>=0&&j>=0;){
if(turn[i][j] == 'U') i--;
else if(turn[i][j] == 'L') j--;
else{
ans.push_back(s1[i]);
i--;
j--;
}
}
// output
reverse(ans.begin(),ans.end());
return ans;
}
};
最大公共子串
需要连续
class Solution {
public:
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
string LCS(string str1, string str2) {
int m = str1.length(), n = str2.length();
if (m == 0 || n == 0)
return nullptr;
vector<vector<int>> dp(m, vector<int>(n));
int index = 0, maxsum = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (str1[i] == str2[j]) {
if (i == 0 || j == 0)
dp[i][j] = 1;
else
dp[i][j] = dp[i - 1][j - 1] + 1;
if (maxsum < dp[i][j])
maxsum = dp[i][j], index = i;
}
}
}
return maxsum == 0 ? "-1" : str1.substr(index - maxsum + 1, maxsum);
}
};
二、重点题
2877 排序题,只限制相邻的可以交换位置,求最小的交换次数。其实就是求逆序数
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
int main() {
int T, n;
cin >> T;
int num[1010];
for (int i = 1; i <= T; i++) {
cin >> n;
int sum = 0;
for (int j = 0; j < n; j++) {
cin >> num[j];
}
for (int j = 0; j < n; j++) {
for (int m = j + 1; m < n; m++) {
if (num[j] > num[m])
sum++;
}
}
cout << "Scenario #" << i << ":" << endl;
cout << sum << endl << endl;
}
return 0;
}
2971 数学题,数字上所有位数加起来能被3整除时,这个数能被3整除
考虑样例中的2 8,那么相当于考虑18,28,38,…,98中有几个能被3整除。
我们知道当数字上所有位数加起来能被3整除时,这个数能被3整除,而我们可以将1-9分成三组:369,147,258,分别是模3余0,1,2三种情况,因为个位不变的,那么不管个位是几,总能找到合适的一组去匹配它,使得其加上个位后被3整除,所以个数就是3.
容易知道这个结论是可以推广到n位的.
那么我们只需要计算99…9-10…0中能被3整除的有几个数,即(99…9-10…0+1)/3
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
for(int a = 0; a < T; ++a){
int c, w;
cin >> c >> w;
int start = (int)pow(10, c-2);
int end = 0;
for(int i = 0; i < c-1; ++i){
end = end*10+9;
}
int count = end-start+1;
printf("case #%d:\n%d\n", a, count/3);
}
return 0;
}