算法日志篇

1.小试牛刀

A - Two Rectangles (AtCoder - abc052_a)

Time Limit: 2 sec / Memory Limit: 256 MB

Problem Statement
There are two rectangles. The lengths of the vertical sides of the first rectangle are A, and the lengths of the horizontal sides of the first rectangle are B. The lengths of the vertical sides of the second rectangle are C, and the lengths of the horizontal sides of the second rectangle are D.
Print the area of the rectangle with the larger area. If the two rectangles have equal areas, print that area.
Constraints
All input values are integers.
1≤A≤ 1 0 4 10^4 104
1≤B≤ 1 0 4 10^4 104
1≤C≤ 1 0 4 10^4 104
1≤D≤ 1 0 4 10^4 104
Input
The input is given from Standard Input in the following format:
A B C D
Output
Print the area of the rectangle with the larger area. If the two rectangles have equal areas, print that area.
Sample Input 1
3 5 2 7
Sample Output 1
15
The first rectangle has an area of 3×5=15, and the second rectangle has an area of 2×7=14. Thus, the output should be 15, the larger area.
Sample Input 2
100 600 200 300
Sample Output 2
60000
题解:
判断两个矩形的大小即可

#include<iostream>
using namespace std;
int solve(){
	int A,B,C,D;
	cin >> A >> B >> C >> D;
	int S1,S2;
	S1 = A * B;
	S2 = C * D;
	if(S1 > S2)cout << S1;
	else cout << S2;
}
int main(){
	solve();
	return 0;
}

B - Increment Decrement(AtCoder - abc052_b)

Time Limit: 2 sec / Memory Limit: 256 MB

Problem Statement
You have an integer variable x. Initially, x=0.Some person gave you a string S of length N, and using the string you performed the following operation N times. In the i-th operation, you incremented the value of
x by 1 if Si =I, and decremented the value of x by 1 if Si=D.
Find the maximum value taken by x during the operations (including before the first operation, and after the last operation).
Constraints
1≤N≤100
∣S∣=N
No characters except I and D occur in S.
Input
The input is given from Standard Input in the following format:
N
S
Output
Print the maximum value taken by x during the operations.
Sample Input 1
5
IIDID
Sample Output 1
2
After each operation, the value of x becomes 1, 2, 1, 2 and 1, respectively. Thus, the output should be 2, the maximum value.
Sample Input 2
7
DDIDDII
Sample Output 2
0
The initial value x=0 is the maximum value taken by x, thus the output should be 0.
题解
按照题意一直向后模拟

#include<iostream>
#include<string>
using namespace std;
int main(){
	int n;
	string str;
	cin >> n >> str ;
	int count = 0;
	int res = 0;
	for(int i = 0;i < n;i ++){
		if(str[i] == 'D')count--;
		else count ++;
		if(count > res)res = count;
	}
	cout << res;
	return 0;
}

A. Theatre Square (CodeForces - 1A)

Problem Statement
Theatre Square in the capital city of Berland has a rectangular shape with the size n × m meters. On the occasion of the city’s anniversary, a decision was taken to pave the Square with square granite flagstones. Each flagstone is of the size a × a.

What is the least number of flagstones needed to pave the Square? It’s allowed to cover the surface larger than the Theatre Square, but the Square has to be covered. It’s not allowed to break the flagstones. The sides of flagstones should be parallel to the sides of the Square.

Input
The input contains three positive integer numbers in the first line: n,  m and a (1 ≤  n, m, a ≤ 109).

Output
Write the needed number of flagstones.

Examples
input
6 6 4
output
4

题解
思维题,根据格子大小进行分割,如果最后有多余的格子不能覆盖的话则需要+1.

#include<iostream>
using namespace std;
int main(){
	long long n,m,a;
	cin >> n >> m >> a;
	long long num_l , num_w = 0;
	if(n % a == 0)num_l = n/a;
	else num_l = n/a+1;
	if(m % a == 0)num_w = m/a;
	else num_w = m/a+1;
	long long res = 0;
	res = num_l * num_w;
	cout << res;
	return 0;
} 

F - Simple Math Problem 1 (Gym - 383403F)

ask ∑ i = 1 n \sum_{i=1}^n i=1n ( − 1 ) i ∗ i (-1)^i*i (1)ii

Input
In the only line given n(1≤n≤1012)

Output
Print a single line containing answer.

题解
找规律题,在纸上列出前n项后可得出每一项的规律:
1 2 3 4 5分别对应了-1 1 -2 2 -3 3,可得到如果n是奇数,则此时输出-(n / 2 + 1)若n是偶数则输出n / 2。

#include<iostream>
using namespace std;
int main(){
	long long n;
	cin >> n;
	if(n%2 == 0){
		cout << n / 2;
	}
	else cout << -(n / 2 + 1);
	return 0;
}

G - zr学姐与迷弟(Gym - 383403B)

众所周知,zr学姐美丽动人,吸引了众多迷弟。迷弟那么多,他都快不好意思了!于是她打算请迷弟们喝奶茶。但是奶茶不够分啊!于是zr学姐想出了一个办法,把迷弟们的成绩搜集起来,排个序,成绩好的优先,嘿嘿。如果两个人成绩一样,就按照字典序的顺序进行排序。zr学姐去买奶茶了,你能帮她完成这个任务吗?

Input
第一行一个数字n(1 ≤ n ≤ 20)表示人数。 接下来n行每行一个字符串s(1 ≤ len(s) ≤ 20)和一个数字k(0 ≤ k ≤ 100),表示迷弟的名字和成绩。(字符串仅包含小写字母)

Output
输出排序之后的结果,每个字符串一行

Sample 1
Input
15
myj 98
ddl 98
cd 98
hzy 98
ljz 100
wlk 59
kfccrazythursdayvme 50
cxk 38
dingzhenzhenzhu 0
dingzhen 0
donghuangtai 1
tiansuohao 2
jieerlian 3
renshengzigushui 54
iphone 14
Output
ljz
cd
ddl
hzy
myj
wlk
renshengzigushui
kfccrazythursdayvme
cxk
iphone
jieerlian
tiansuohao
donghuangtai
dingzhen
dingzhenzhenzhu

题解
排序题,设定好排序规则即可

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct Boy{
	string name;
	int score;
}boy[21];
bool comparsion(Boy a,Boy b)
{
	return a.name<b.name;
}
bool comparsion_score(Boy a,Boy b){
	return a.score>b.score;
}
int main(){
	int n;
	cin >> n;
	for(int i = 0;i < n;i++){
		cin >> boy[i].name >> boy[i].score;
	}
	sort(boy,boy+n,comparsion);
	sort(boy,boy+n,comparsion_score);
	for(int i = 0;i < n;i++){
		cout << boy[i].name << endl;
	}
	return 0;
}

H - Text Reverse (HDU - 1062)

Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them.
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single line with several words. There will be at most 1000 characters in a line.
Output
For each test case, you should output the text which is processed.
Sample
Input
3
olleh !dlrow
m’I morf .udh
I ekil .mca
Output
hello world!
I’m from hdu.
I like acm.
Hint
Remember to use getchar() to read ‘\n’ after the interger T, then you may use gets() to read a line and process it.
题解
开辟一个栈作为字符进入的中间场所,根据栈的先进后出原则,将每一个单词依次弹入栈,直到遇见空格,在将栈内的字母依次输出,则可实现将某一个单词的序列逆置,并且在结束后要注意加上空格。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int n; 
	stack<char> c;
	string str1;
	string str2;
	cin >> n;
	getline(cin,str1);
	str2.resize(str1.length());
	while(n --){
		getline(cin,str1);
		str2.resize(str1.length());
		int j = 0;
        for(int i=0; i<str1.length(); i++)
        {
            if(str1[i] != ' ')
                c.push(str1[i]);
            else
            {
                while(!c.empty())
                {
                    str2[j++] = c.top();
                    c.pop();
                }
                str2[j++] = ' ';
            }
        }
        while(!c.empty())
        {
            str2[j++] = c.top();
            c.pop();
        }
        cout << str2 << endl;
	}
	return 0;
}

I - Walk and Teleport (AtCoder - arc067_b)

Problem Statement
There are N towns on a line running east-west. The towns are numbered
1 through N, in order from west to east. Each point on the line has a one-dimensional coordinate, and a point that is farther east has a greater coordinate value. The coordinate of town i is X i​ .
You are now at town 1, and you want to visit all the other towns. You have two ways to travel:
1.Walk on the line. Your fatigue level increases by A each time you travel a distance of 1, regardless of direction.
2.Teleport to any location of your choice. Your fatigue level increases by B, regardless of the distance covered.
Find the minimum possible total increase of your fatigue level when you visit all the towns in these two ways.
Input
The input is given from Standard Input in the following format:
N A B
X1 X2 … XN
Output
Print the minimum possible total increase of your fatigue level when you visit all the towns.
Sample Input 1
4 2 5
1 2 5 7
Sample Output 1
11
From town 1, walk a distance of 1 to town 2, then teleport to town 3, then walk a distance of 2 to town 4. The total increase of your fatigue level in this case is 2×1+5+2×2=11, which is the minimum possible value.
Sample Input 2
7 1 100
40 43 45 105 108 115 124
Sample Output 2
84
From town 1, walk all the way to town 7. The total increase of your fatigue level in this case is 84, which is the minimum possible value.
Sample Input 3
7 1 2
24 35 40 68 72 99 103
Sample Output 3
12
Visit all the towns in any order by teleporting six times. The total increase of your fatigue level in this case is 12, which is the minimum possible value.
题解
两种方式:第一种是直接从前一个到后一个城市,花费的精力是两座城市之间的举例,第二种是通过传送到达,花费的精力是b的值,只需判断每次行走所花费的精力大还是传送所花费的精力大再依次相加即可。

#include <bits/stdc++.h>
using namespace std;
int main(){
	long long n,a,b;
	long long res = 0;
	cin >> n >> a >> b;
	long long town[n]={0};
	for(int i = 0;i < n;i ++){
		cin >> town[i];
	}
	for(int i = 1;i < n;i ++){
		if(b > a*(town[i]-town[i-1])) res = a*(town[i]-town[i-1]) + res;
		else res = b + res;
	}
	cout << res;
	return 0;
}

J - Factors of Factorial (唯一分解定理) (AtCoder - arc067_a)

Problem Statement
You are given an integer N. Find the number of the positive divisors of
N!, modulo 1 0 9 + 7 10^9+7 109+7
Constraints
1≤N≤ 1 0 3 10^3 103
Input
The input is given from Standard Input in the following format:
N
Output
Print the number of the positive divisors of N!, modulo 1 0 9 + 7 10^9+7 109+7
Sample Input 1
3
Sample Output 1
4
There are four divisors of 3! =6: 1, 2, 3 and 6. Thus, the output should be 4.
Sample Input 2
6
Sample Output 2
30
Sample Input 3
1000
Sample Output 3
972926972
题解
先介绍一下唯一分解定理
基本概念:
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,叫做这个合数的分解质因数。 分解质因数只针对合数。
并且,每个合数能够且仅仅能够被分解为唯一一组质因数的乘积。
在这里插入图片描述
根据第一条就可以求出此题要我们待求的结果

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
// 计算N!的正因子数量
int countDivisorsOfFactorial(int N) {
    vector<int> primeCounts(N + 1, 0);
    // 计算每个从1到N的数的质因数分解
    for (int i = 2; i <= N; ++i) {
        int num = i;
        for (int j = 2; j * j <= num; ++j) {
            while (num % j == 0) {
                primeCounts[j]++;
                num /= j;
            }
        }
        if (num > 1) {
            primeCounts[num]++;
        }
    }
    // 计算正因子的数量
    long long totalDivisors = 1;
    for (int count : primeCounts) {
        totalDivisors = (totalDivisors * (count + 1)) % MOD;
    }
    return static_cast<int>(totalDivisors);
}
int main() {
    int N;
    cin >> N;
    int result = countDivisorsOfFactorial(N);
    cout << result << endl;
    return 0;
}

K - 质数筛 (埃氏筛模板) (洛谷 - P5736)

题目描述
输入 n 个不大于 1 0 5 10^5 105的正整数。要求全部储存在数组中,去除掉不是质数的数字,依次输出剩余的质数。

输入格式
第一行输入一个正整数 n,表示整数个数。
第二行输入 n 个正整数 ai,以空格隔开。

输出格式
输出一行,依次输出 ai中剩余的质数,以空格隔开。

输入输出样例
输入
5
3 4 5 6 7
输出
3 5 7

题解
首先是埃氏筛,也叫素数筛:如果我们要得到自然数n以内的全部素数,把不大于根号n的所有素数的倍数剔除,剩下的就是素数。

import java.io.*;
import java.util.*;
public class Main
{
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int n = (int) 1e5;
        int z;
        z = s.nextInt();
        List<Integer> list=new ArrayList<>();
        int[] prime = new int[n];
        Arrays.fill(prime,1);
        for(int i = 2;i * i <= n;i ++){
            if(prime[i] == 1){
                for (int j =i * i; j < n; j = j + i)
                {
                    prime[j] = 0;
                }
            }
        }
        for(int i = 0;i < z;i ++){
            int x;
            x = s.nextInt();
            if(prime[x] == 1 && x != 1) System.out.print(x + " ");
        }
    }
}

L - Sum of Divisors (求解 1~n因子个数) (AtCoder - abc172_d )

Problem Statement
For a positive integer X, let f(X) be the number of positive divisors of X.
Given a positive integer N, find ∑ K = 1 N K × f ( K ) \sum_{K=1}^{N}K×f(K) K=1NK×f(K)

Constraints
1≤N≤ 1 0 7 10^7 107

Input
Input is given from Standard Input in the following format:
N
Output
Print the value ∑ K = 1 N K × f ( K ) \sum_{K=1}^{N}K×f(K) K=1NK×f(K)

Sample Input 1
4
Sample Output 1
23
We have f(1)=1, f(2)=2, f(3)=2, and f(4)=3, so the answer is 1×1+2×2+3×2+4×3=23.

题解

#include <iostream>
#include <vector>
using namespace std;
vector<long long> calculateFactorsCount(long long n) {
    vector<long long> factorsCount(n + 1, 0);

    for (long long i = 1; i <= n; ++i) {
        for (long long j = i; j <= n; j += i) {
            factorsCount[j]++;
        }
    }
    return factorsCount;
}
int main() {
    long long n;
    cin >> n;
    long long res = 0;
    vector<long long> factorsCount = calculateFactorsCount(n);
    for (long long i = 1; i <= n; ++i) {
        res = factorsCount[i] * i + res;
    }
    cout << res ;
    return 0;
}

M - How Much Does Daytona Cost? (CodeForces - 1878A)

Problem Statement
We define an integer to be the most common on a subsegment, if its number of occurrences on that subsegment is larger than the number of occurrences of any other integer in that subsegment. A subsegment of an array is a consecutive segment of elements in the array a.
Given an array a of size n, and an integer k, determine if there exists a non-empty subsegment of a where k is the most common element.
在这里插入图片描述
题解

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int a[N];
int main(){
    int t;cin>>t;
    while(t--){
        int n,k,flag=0;
        cin>>n>>k;
        for(int i=0;i<n;i++){
            cin>>a[i];
            if(a[i]==k){
                flag=1;
            }
        }
        if(flag==1) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

N - 数字直角三角形(洛谷 - P5721)

题目描述
给出 n,请输出一个直角边长度是 n 的数字直角三角形。所有数字都是2 位组成的,如果没有2 位则加上前导0。
输入格式
输入一个正整数 n。
输出格式
输出如题目要求的数字直角三角形。
在这里插入图片描述
题解
直接拼接就好了

#include <iostream>
using namespace std;
int main() {
    int n;
    cin >> n;
    int x = n;
    int count = 1;
    for(int i = 0;i < n;i ++){
        for(int j = x;j > 0;j --){
            if(count < 10)cout << '0' << count ;
            else cout << count;
            count ++;
        }
        x -= 1;
        cout << endl;
    }
    return 0;
}

O - Noldbach problem (CodeForces - 17A)

Problem Statement
Nick is interested in prime numbers. Once he read about Goldbach problem. It states that every even integer greater than 2 can be expressed as the sum of two primes. That got Nick’s attention and he decided to invent a problem of his own and call it Noldbach problem. Since Nick is interested only in prime numbers, Noldbach problem states that at least k prime numbers from 2 to n inclusively can be expressed as the sum of three integer numbers: two neighboring prime numbers and 1. For example, 19 = 7 + 11 + 1, or 13 = 5 + 7 + 1.
Two prime numbers are called neighboring if there are no other prime numbers between them.
You are to help Nick, and find out if he is right or wrong.
Input
The first line of the input contains two integers n (2 ≤ n ≤ 1000) and k (0 ≤ k ≤ 1000).
Output
Output YES if at least k prime numbers from 2 to n inclusively can be expressed as it was described above. Otherwise output NO.
在这里插入图片描述
题解
求n以内等于两个连续素数的和加上1的数的个数 n不大于1000;

#include <iostream>
#include <vector>
using namespace std;
bool isPrimer(int n){
    if (n < 2) {
        return false;
    }
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            return false; 
        }
    }
    return true; 
}
int main() {
    int n,k;
    int index = 0;
    int count = 0;
    cin >> n >> k;
    vector<int> primerNum(n + 1,0);
    for(int i = 0;i <= n;i ++){
        if(isPrimer(i)){
            primerNum[index] = i;
            index ++;
        }
    }
    for(int i = 0;primerNum[i] != 0 && primerNum[i] + primerNum[i + 1] + 1 <= n;i++){
        if(isPrimer(primerNum[i] + primerNum[i + 1] + 1)){
            count ++;
        }
    }
    if(count >= k)cout << "YES";
    else cout << "NO";
    /*cout << count <<endl;
    for(int i = 0;i < n;i ++){
        cout << primerNum[i] <<" ";
    }*/
    return 0;
}

P - 质因子分解(洛谷 - P2043)

题目描述
对 N! 进行质因子分解。
输入格式
输入数据仅有一行包含一个正整数 N,N≤10000。
输出格式
输出数据包含若干行,每行两个正整数 p,a,中间用一个空格隔开。表示 N! 包含 a 个质因子 p,要求按 p 的值从小到大输出。
在这里插入图片描述
题解
不能直接求解 N!,因为我们知道 C++ 中固有数据类型中,能表示最大的数据为 2^64-1,也就是 unsigned long long 类型。而题目中给出的 N 最大值为 1000,固不能直接求。

#include <iostream>
#include <vector>
using namespace std;
bool isPrimer(int n){
    if (n < 2) {
        return false;
    }
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            return false; 
        }
    }
    return true; 
}
int main() {
    int n;
    cin >> n;
    vector<int> primeCounts(n + 1, 0);
    // 计算每个从1到N的数的质因数分解
    for (int i = 2; i <= n; ++i) {
        int num = i;
        for (int j = 2; j * j <= num; ++j) {
            while (num % j == 0) {
                primeCounts[j]++;
                num /= j;
            }
        }
        if (num > 1) {
            primeCounts[num]++;
        }
    }
    for(int i = 2;i < primeCounts.size();i ++){
        if(isPrimer(i))cout << i << ' ' << primeCounts[i] <<endl;
    }
    return 0;
}

Q - Aleksa and Stack (CodeForces - 1878B)

Problem Statement
After the Serbian Informatics Olympiad, Aleksa was very sad, because he didn’t win a medal (he didn’t know stack), so Vasilije came to give him an easy problem, just to make his day better.
Vasilije gave Aleksa a positive integer n(n≥3) and asked him to construct a strictly increasing array of size n of positive integers, such that
·3⋅ai+2is not divisible by ai+ai+1 for each i (1≤i≤n−2).
Note that a strictly increasing array a of size n is an array where ai<ai+1 for each i (1≤i≤n−1).
Since Aleksa thinks he is a bad programmer now, he asked you to help him find such an array.
Input
Each test consists of multiple test cases. The first line contains a single integer t (1≤t≤10^4) — the number of test cases. The description of test cases follows.
The first line of each test case contains a single integer n
(3≤n≤2⋅10^5) — the number of elements in array.
It is guaranteed that the sum of n over all test cases does not exceed 2⋅10^5.
Output
For each test case, output nintegers a1,a2,a3,…,an
(1≤ai≤10^9).
It can be proved that the solution exists for any n. If there are multiple solutions, output any of them.
在这里插入图片描述
题解
这道题题意大概是,给定一个n,要求我们构造一个序列,使得对于每个下标i,都满足3ai+2%(ai + ai…
那么我们可以发现,如果序列中全是奇数的话,奇数+奇数=偶数,奇数
3=奇数,偶数是不可能整除奇数的,因此就找到一个满足题意的构造了。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int main(){
    int n;
    int begin = 1;
    cin >> n;
    while(n --){
        int x;
        cin >> x;
        int res[x]={0};
        for(int i = 0;i < x;i ++){
            res[i] = begin;
            begin += 2;
        }
        begin = 1;
        for(int i = 0;i < x; i ++){
            cout << res[i] << ' ';
        }
    }
    return 0;
}

R - 进制转换 (洛谷 - P2084)

在这里插入图片描述
题解
注意:任何进制之间进行转换时最好都以十进制作为中介。

#include <bits/stdc++.h>

using namespace std;

//const int N = 1e6 + 10;

int main(){
    int m;
    string n;
    cin >> m >> n;
    int length = n.size();
    int index = length - 1;
    for(int i = 0;i < length;i ++,index --){
        if(i!=0 && n[i]!='0') cout << '+';
        if (n[i] == '0') continue;
        cout << n[i] << '*' << m << '^' << index;
    }
    return 0;
}

S - Almost Prime(CodeForces - 26A )

在这里插入图片描述
题解
一个恰好有2个质因数的数被称为“半素数”,请求出1到n中有多少个半素数。例如,6,12,18,35为半素数,而30,2,4,8,9不是半素数。打表+set,题意是输出1-n中几乎质数的数量,几乎质数就是有两个不同质数的除数,即有两个不同的质因子,这里开一个前缀和数组sum,下标存放的是1-i的几乎质数的个数,因为集合的去重性,用集合才存储不同的质因子,一旦szie等于2则说明该数是几乎质数。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int sum[N]={0};
int main()
{
	bool check(int);
	for(int i = 1;i <= N;i ++)
	{
		if(check(i))
		  sum[i] = sum[i - 1] + 1;
		else
		  sum[i] = sum[i - 1];  
	}
	int n;
	cin >> n;
	cout << sum[n] << endl;
	return 0;
}
bool check(int s)
{
	set<int >beg;
	for(int i = 2;i * i <= s;i ++)
	  while(s % i == 0)
	  {
	  	beg.insert(i);
	  	s /= i;
	  }
	if(s != 1)
	  beg.insert(s);
	if(beg.size() == 2)
	  return true;
	return false;    
}

T - 级数求和 (洛谷 - P1035)

题解
直接暴力,不需要什么方法。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int main()
{
	double k;
    cin >> k;
    double i = 1,res = 0;
    while(res <= k * 1.0){
        res += 1/i;
        i ++;
    }
    cout << i - 1;
	return 0;
}

U - Forming Triangles (CodeForces - 1922B)

在这里插入图片描述
在这里插入图片描述
题解
按照长度记录
就两种情况合法
1、同种长度选两个,再选一个短的
2、同种长度选三个

#include<bits/stdc++.h>
#define yes cout<<"Yes"<<endl
#define no cout<<"No"<<endl
#define endl "\n"
using namespace std;
using ll = long long;
using db = double;
const int maxn = 1e6;
const int N = 1e9;

ll comb2(ll x) {
	// x个里面选两个
	if (x < 2)return 0;
	return x * (x-1) / 2ll;
}

ll comb3(ll x) {
	// x个里面选三个
	if (x < 3)return 0;
	return x * (x - 1) * (x - 2) / 6ll;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		vector<int> a(n + 1);
		map<int, ll> cnt;
		for (int i = 1; i <= n; i++) {
			cin >> a[i]; cnt[a[i]]++;
		}
		
		ll ans = 0;
		ll sum = 0;
		for (auto i : cnt) {
			ll now = i.second;
			ans += comb3(now); // 计算等边
			ans += comb2(now) * sum; // 计算等腰
			sum += now;
		}
		cout << ans << endl;
	}
	return 0;
}

V - 进制转换2 (洛谷 - P1143)

在这里插入图片描述

题解
cul为字母转数字,pf为数字转字母打印,若涉及进制转换时切记要先将待转进制转化为十进制,再有十进制转化为目标进制。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int cul(char x){
    if(x >= 'A'){
        return  x - 'A' + 10;
    }else{
        return x - '0';
    }
}

char pf(int x){
    if(x >= 10){
        return x - 10 + 'A';
    }else{
        return x + '0';
    }
}

void solve(){
    int n,m;
    string s;
    string ans;
    cin >> n >> s >> m;
    int res = 0;
    for(int i = 0;i < s.length();i ++){
        res = res * n + cul(s[i]);
    }
    while(res > 0){
        ans = pf(res % m) + ans;
        res /= m; 
    }
    cout << ans;
}

int main()
{
	solve();
    return 0;
}

W - 线性筛素数 (洛谷 - P3383)

在这里插入图片描述

题解
基本思想
当前数字是n=p1^a * p2^b * p3^c(p1<p2<p3且均为素数),一次循环筛除小于等于p1的素数乘以n得到的数。比如p1之前有pi,pj和pk三个素数,则此次循环筛掉pin,pjn,pkn和p1n ,prime 里的素数都是升序排列的,break时的prime[j] 就是这里的p1。
优点:没有重复筛同一个数
原因:按照一个数的最小素因子筛选,比如6只按2筛去

第一次第二次第三次第四次第五次第六次第七次
第一次2x2
第二次3x23x3
第三次4x2
第四次5x25x35x5
第五次6x2
第六次7x27x37x57x7

从图上我们看到,第一列筛掉的是最小素因子是2的数,第二列筛掉的是最小素因子为3的数,依次类推,可以把所有的合数都筛掉
因为是按照最小素因子筛选,所以可以保证每个数都只会被筛一遍

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    vector<int> prime;
    vector<int> v(n + 1);
    for (int i = 2; i <= n; i++)
    {
        if (!v[i])
        {
            v[i] = i;
            prime.push_back(i);
        }
        for (int j : prime)
        {
            if (j > v[i] || j * i > n)
                break;
            v[j * i] = v[i];
        }
    }
    int q;
    cin >> q;
    while (q--)
    {
        int x;
        cin >> x;
        cout << prime[x - 1] << "\n";
    }
}

X - 排队接水 (洛谷 - P1223)

在这里插入图片描述题解
由这道题想到操作系统进程调度中的SJF算法(最短剩余时间优先)类比此算法可得到只需要从小到大排列并计算输出,就可以得到最短时间。

import java.io.*;
import java.util.*;

public class Main
{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            double n = sc.nextDouble();
            double m = 0;
            double h = n - 1;
            double x[] = new double[(int) n];
            double y[] = new double[x.length];  //记录每个数据的编号
            int z[] = new int[x.length];       //记录每个数据的编号是否输出
            for (int i = 0; i < n; i++) {
                x[i] = sc.nextInt();
                y[i] = x[i];
            }
            Arrays.sort(x);
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (y[j] == x[i] && z[j] == 0) {
                        if (i == n - 1) {
                            System.out.println(j + 1);
                        } else {
                            System.out.print(j + 1+" ");
                        }
                        z[j] = 1;
                        break;
                    }
                }
            }
            for (int i = 0; i < n; i++) {
                m += x[i] * (h--);
            }
            System.out.println(String.format("%.2f", m / n));
        }
    }
}

Y - 车厢重组 (洛谷 - P1116)

在这里插入图片描述
题解
此题实际上就是模拟冒泡排序,只要模拟冒泡排序的方式进行一次完整的排序过程,并在其中记录下元素的移动次数,即可得到答案。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n = 0;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    int cnt = 0;
    for (int j = 0; j < n-1; ++j) {
        for (int i = 0; i < n-j-1; ++i) {
            if (a[i] > a[i+1]) {
                swap(a[i], a[i+1]);
                cnt++;
            }
        }
    }
    cout << cnt << endl;
    return 0;
}

Z - 统计方形(数据加强版) (洛谷 - P2241)

在这里插入图片描述
题解
画图可知
首先,统计一个nm的矩形里有多少个正方形,长方形。
要明确,正方形和长方形都是矩形,那么n
m的矩形里的
矩形数=正方形数+长方形数

import java.io.*;
import java.util.*;

public class Main
{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        long sum1 = 0;//正方形
        long sum2 = 0;//矩形个数
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                sum1 += Math.min(i, j);
                sum2 += i * j;
            }
        }
        System.out.println(sum1 + " " + (sum2 - sum1));
    }
}

AA - 求区间和 (洛谷 - B3612)

在这里插入图片描述
题解
前缀和差分模板题。
定义一个数组存放数列an的前缀和。
有了前缀和之后,我们可以使用差分来进行静态的区间求和。具体而言,对于一个区间
[l,r],区间的和 al + al+1 +…+ar = Sr - Sl-1

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    vector<long long> v(n + 1);
    vector<long long> pre(n + 1);

    for(int i = 1;i <= n;i ++){
        long long n;
        cin >> n;
        v[i] = n;
        pre[i] = pre[i - 1] + n;
    }
    int x;
    cin >> x;
    while(x --){
        int r,l;
        cin >> l >> r;
        cout << pre[r] - pre[l - 1] << "\n";
    }
} 

AB - 语文成绩 (洛谷 - P2367)

在这里插入图片描述
题解
差分,先从这个词的构成角度来看,应该是与两数之差以及分块思想有关。
让我们先给定一个简单数列:
arr[1] = 1;
arr[2] = 2;
arr[3] = 4;
接下来定义差分:
//d数组记录的就是差分
d[1] = arr[1] = 1;
d[2] = arr[2] - arr[1] = 1;
d[3] = arr[3] - arr[2] = 2;
d[4] = 0 - arr[3] = -4;
显而易见,差分数组 d 记录的就是数列中一个数和它前面的那个数之差。
差分的一些基本性质:
性质1:将原序列区间[L,R]中的元素全部 + k,可以转化操作为差分序列L处 + k,R+1处 - k。
如对上述序列区间[2,3]每个数加1,即:
arr[2] = 3; arr[3] = 5;
再看差分数组d
d[2] = arr[2] - arr[1] = 2; d[4] = 0 - arr[3] = -5;
性质2:差分序列求前缀和可得原序列
先说一下前缀和是什么。
前缀和,顾名思义,即一段序列的前 i 项之和。 其实就类似于数列的前n项和。
定义数组 s 保存上述差分数列的前缀和。
s[1] = d[1] = 1;
s[2] = d[2] + d[1] = 2;
s[3] = d[3] + d[2] + d[1] = 4;

#include <bits/stdc++.h>
#define MAXN 5000010
using namespace std;

int n, q;
int a[MAXN]; // 前缀和
int b[MAXN]; // 查分数组

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> q;
	for (register int i = 1; i <= n; i++)
	{
		cin >> a[i];
		b[i] = a[i] - a[i - 1];
	}
	int x , y, z;
	while (q--)
	{
		cin >> x >> y >> z;
		b[x] += z;
		b[y + 1] -= z;
	}
	int ans = INT_MAX;
	for (register int i = 1; i <= n; i++)
	{
		a[i] = a[i - 1] + b[i];
		ans = min(ans, a[i]);
	}
	cout << ans << endl;
	return 0;
}

AC - 领地选择 (洛谷 - P2004)

在这里插入图片描述
题解
此题用到了二位前缀和
二维前缀和是一种用于处理二维数组区域求和查询的方法。它先计算一个前缀和数组,然后利用这个数组来快速回答任何区域和的查询。
假设我们有一个二维数组,如下所示:
1 2 3
4 5 6
7 8 9
我们首先计算二维前缀和数组,其中每个元素 (i, j) 的值是原数组中从 (0, 0) 到 (i, j) 形成的矩形区域内所有元素的和。计算公式为:prefixSum[i][j] = original[i][j] + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1]。
计算二维前缀和的步骤:
1.初始化前缀和数组:创建一个与原数组同样大小的数组,用于存储前缀和。
2.计算前缀和:
对于数组中的每个元素 (i, j),计算其前缀和。前缀和定义为从原数组的左上角 (0, 0) 到当前位置 (i, j) 所包含的所有元素的和。
计算公式为:prefixSum[i][j] = original[i][j] + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1]。
original[i][j] 是当前元素的值。
prefixSum[i-1][j] 是当前元素上方元素的前缀和。
prefixSum[i][j-1] 是当前元素左侧元素的前缀和。
prefixSum[i-1][j-1] 是当前元素左上角元素的前缀和,需要减去避免重复计算。
3.边界情况处理:
当 i 或 j 为 0 时,需要特别处理,因为此时没有左侧或上方的元素。
具体可以参考:二维前缀和ps:这个佬写的很细致。

#include <bits/stdc++.h>
using namespace std;
int main(){
    long long n , m , c;
    cin >> n >> m >>c;
    long long map[n+1][m+1];
    long long add[n+1][m+1];
    for(long long i = 1;i <= n; i ++){
        for(long long j = 1;j <= m;j ++){
            cin >> map[i][j];
            add[i][j] = add[i - 1][j] + add[i][j - 1] - add[i - 1][j - 1] + map[i][j];
        }
    }
    long long M = 0,x,y;
    for(long long i = c;i <= n;i ++){
        for(long long j = c;j <= m;j ++){
            if(add[i][j] + add[i - c][j - c] - add[i - c][j] - add[i][j - c] > M){
				long long ace = add[i][j] + add[i - c][j - c] - add[i - c][j] - add[i][j - c];
				M = ace;
				x = i,y = j;
			}
        }
    }
	cout << x - c + 1 << " " << y - c + 1 << endl;
    return 0;
}

AD - 最大正方形 (洛谷 - P1387)

在这里插入图片描述
题解
也可以用二维前缀和来写,通过循环来设置每个二维前缀和的基准,如果某个矩形的长乘宽等于其二位前缀和,则其中不包括0。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int map[105][105];
    int add[105][105];
    int n ,m ,s ,ans = 0;
    cin >> n >> m; 
    s = min(n,m);
    for(int i = 1;i <= n;i ++){
        for(int j = 1;j <= m;j ++){
            cin >> map[i][j];
            add[i][j] = add[i - 1][j] + add[i][j - 1] - add[i - 1][j - 1] + map[i][j];
        }
    }
    for(int i = 1;i <= n;i ++){
        for(int j = 1;j <= m;j ++){
            for(int k = ans;k <= s;k ++){
                int x = i + k - 1; 
                int y = j + k - 1;
                if(x > n || y > m || add[i - 1][j - 1] - add[x][j - 1] - add[i - 1][y] + add[x][y] != k * k) break;
                if(ans < k) ans = k;
            }
        }
    }
    cout<<ans;
    return 0;
}
  • 37
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值