专注 效率 记忆
预习 笔记 复习 做题
欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)
文章字体风格:
红色文字表示:重难点★✔
蓝色文字表示:思路以及想法★✔
如果大家觉得有帮助的话,感谢大家帮忙
点赞!收藏!转发!
本博客带大家一起学习,我们不图快,只求稳扎稳打。
由于我高三是在家自学的,经验教训告诉我,学习一定要长期积累,并且复习,所以我推出此系列。
只求每天坚持40分钟,一周学5天,复习2天
也就是一周学10道题
60天后我们就可以学完81道题,相信60天后,我们一定可以有扎实的代码基础!我们每天就40分钟,和我一起坚持下去吧!
qq群:878080619
#include
#include
#include
using namespace std;
const int N = 1010;
int n, m;
struct Person
{
string name;
int score;
int id;
bool operator< (const Person& t) const
{
if (score != t.score) return score < t.score;
return id < t.id;
}
bool operator> (const Person& t) const
{
if (score != t.score) return score > t.score;
return id < t.id;
}
}q[N];
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
cin >> q[i].name >> q[i].score;
q[i].id = i;
}
if (!m) sort(q, q + n, greater<Person>());
else sort(q, q + n);
for (int i = 0; i < n; i ++ )
cout << q[i].name << ' ' << q[i].score << endl;
return 0;
}
#include
using namespace std;
struct node{
int x,id;
string name;
}a[1001];
bool cmp1(node a,node b){
//从小到大
if(a.x==b.x)return a.id<b.id;
return a.x<b.x;
}
bool cmp2(node a,node b){
//从大到小
if(a.x==b.x)return a.id<b.id;
return a.x>b.x;
}
int main()
{
int n;
bool ok;
cin>>n>>ok;
for(int i=1;i<=n;i++){
cin>>a[i].name>>a[i].x;
a[i].id=i;
}
if(ok)sort(a+1,a+1+n,cmp1);
if(!ok)sort(a+1,a+1+n,cmp2);
for(int i=1;i<=n;i++)
cout<<a[i].name<<' '<<a[i].x<<'\n';
}
在结构体中定义一个id,记录出现的顺序
// package Test;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author zh
* @Date 2023/8/8 19:10
* @PackageName:Test
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
class Student{
int grade;
String name;
public Student(int grade,String name){
this.grade = grade;
this.name = name;
}
}
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int a = scanner.nextInt();
Student[] students = new Student[N];
for(int i = 0; i < N; i++){
String name = scanner.next();
int grade = scanner.nextInt();
students[i] = new Student(grade,name);
}
if(a == 1){
Arrays.sort(students,(o1, o2) -> {
return o1.grade-o2.grade;
});
}else{
Arrays.sort(students,(o1, o2) -> {
return o2.grade-o1.grade;
});
}
for(Student x : students){
System.out.println(x.name + " " + x.grade);
}
}
}
#include
#include
#include
using namespace std;
const int N = 110;
int n;
struct Person
{
int id;
int score;
bool operator< (const Person& t) const
{
if (score != t.score) return score < t.score;
return id < t.id;
}
}q[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> q[i].id >> q[i].score;
sort(q, q + n);
for (int i = 0; i < n; i ++ ) cout << q[i].id << ' ' << q[i].score << endl;
return 0;
}
import java.util.Arrays;
import java.util.Scanner;
class Student{
int id;
int grade;
public Student(int id,int grade){
this.id = id;
this.grade = grade;
}
}
class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
Student[] students = new Student[n];
for(int i = 0; i < n; i++){
int id = scanner.nextInt();
int grade = scanner.nextInt();
students[i] = new Student(id,grade);
}
Arrays.sort(students,(o1, o2) -> {
if(o1.grade == o2.grade){
return o1.id-o2.id;
}
return o1.grade-o2.grade;
});
for (Student x : students){
System.out.println(x.id + " " + x.grade);
}
}
}
可以csdn搜索一下
关键就是vector的使用 和 除法步骤记得就好
就好比用 代码模拟出 草稿纸上的除法运算
代码看不懂可以,只需明白逻辑,然后自己写即可
一定自己写出来,才明白
#include
#include
#include
#include
using namespace std;
void div(vector<int>& tmp,vector<int>& ans)
{
vector<int> tmp2;
int t = 0;
for(int i = 0; i < tmp.size(); i++)
{
t = t*10 + tmp[i];
tmp2.push_back(t/2);
t = t%2;
}
ans.push_back(t);
reverse(tmp2.begin(),tmp2.end());
while(tmp2.size()!=1 && tmp2.back()==0)
{
tmp2.pop_back();
}
reverse(tmp2.begin(),tmp2.end());
tmp = tmp2;
}
int main()
{
string s;
while(cin >> s)
{
vector<int> tmp;
for(int i = 0; i < s.size(); i++)
{
tmp.push_back(s[i]-'0');
}
vector<int> ans;
//什么时候停止
if(s=="0")
{
cout << 0 << endl;
}
else
{
while(tmp.size()>1 || (tmp.size() == 1 && tmp.back() != 0))
{
div(tmp,ans);
}
reverse(ans.begin(),ans.end());
for(int i = 0; i < ans.size(); i++)
{
cout << ans[i];
}
cout << endl;
}
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
int a, b;
string s;
cin >> a >> b >> s;
vector<int> A;
for (int i = 0; i < s.size(); i ++ )
{
char c = s[s.size() - 1 - i];
if (c >= 'A') A.push_back(c - 'A' + 10);
else A.push_back(c - '0');
}
string res;
if (s == "0") res = "0";
else
{
while (A.size())
{
int r = 0;
for (int i = A.size() - 1; i >= 0; i -- )
{
A[i] += r * a;
r = A[i] % b;
A[i] /= b;
}
while (A.size() && A.back() == 0) A.pop_back();
if (r < 10) res += to_string(r);
else res += r - 10 + 'a';
}
reverse(res.begin(), res.end());
}
cout << res << endl;
return 0;
}
//cpp
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA;
ListNode *p2 = headB;
while (p1 != p2) {
if(p1 != NULL)//p1没有走到结尾
p1 = p1->next;//p1指向下一个节点
else//p1走到结尾
p1 = headB;//p1指向另一个链表头
if(p2 != NULL)//p2没有走到结尾
p2 = p2->next;//p2指向下一个节点
else //p2走到结尾
p2 = headA;//p2指向另一个链表头
}
return p1;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* filterList(ListNode* head) {
bool st[10001] = {};
st[abs(head->val)] = true;
for (auto p = head; p->next;) {
int x = abs(p->next->val);
if (st[x]) {
auto q = p->next;
p->next = q->next;
delete q;
} else {
p = p->next;
st[x] = true;
}
}
return head;
}
};
class Solution {
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
public:
void rearrangedList(ListNode* head) {
// 若只有一个元素,则不需要操作
if (!head->next) {
return;
}
// 计算链表长度
int len = 0;
for (auto p = head; p; p = p->next) {
len++;
}
// 移动到链表中间处
int mid = (len + 1) / 2;
auto a = head;
for (int i = 0; i < mid - 1; i++) {
// 由于该链表没有设头结点,head 就是具有值的结点,因此到 mid - 1
a = a->next;
}
// 反转后半段链表,b在前,c在后
auto b = a->next, c = b->next;
// a->next 是为了从中间将链表截断;b->next 是因为此时的 b 是反转后链表的结尾元素
a->next = b->next = NULL;
while (c) {
auto temp = c->next;
c->next = b;
b = c;
c = temp;
}
// 合并链表,注意此时 b 指向反转链表头部,c 指向 NULL
for (auto p = head, q = b; q;) {
auto qq = q->next;
// 插入结点
q->next = p->next;
p->next = q;
// 移动p和q
p = q->next;
q = qq;
}
}
};
#include
using namespace std;
//平年每月的天数
const int months[] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
//判断是否是闰年
bool is_leap(int y)
{
if(y % 400 == 0 || (y % 100 && y % 4 == 0)) return true;
return false;
}
//获得y年第m月的天数
int get_days(int y, int m)
{
if(m == 2) return months[m] + is_leap(y);
return months[m];
}
//获得y年第m月--y + 1年第m月的的天数
int get_year_days(int y, int m)
{
if(m <= 2) return (365 + is_leap(y));
return (365 + is_leap(y + 1));
}
int main()
{
int t;
cin >> t;
int y, m, d, days;
while(t -- )
{
cin >> y >> m >> d >> days;
if(m == 2 && d == 29)
{
days --;
m = 3, d = 1;
}
while(days > get_year_days(y, m))
{
days -= get_year_days(y, m);
y ++;
}
while(days --)
{
d ++;
if(d > get_days(y, m))
{
m ++, d = 1;
if(m > 12) y ++, m = 1;
}
}
printf("%04d-%02d-%02d\n", y, m, d);
}
return 0;
}
#include
#include
#include
using namespace std;
const int months[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int is_leap(int year) // 闰年返回1,平年返回0
{
if (year % 4 == 0 && year % 100 || year % 400 == 0)
return 1;
return 0;
}
int get_days(int y, int m) // y年m月有多少天
{
if (m == 2) return months[m] + is_leap(y);
return months[m];
}
int main()
{
int y, s;
while (cin >> y >> s)
{
int m = 1, d = 1;
s -- ;
while (s -- )
{
if ( ++ d > get_days(y, m))
{
d = 1;
if ( ++ m > 12)
{
m = 1;
y ++ ;
}
}
}
printf("%04d-%02d-%02d\n", y, m, d);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
stack<int> num;
stack<char> op;
//优先级表
unordered_map<char, int> h{ {'+', 1}, {'-', 1}, {'*',2}, {'/', 2} };
void eval()//求值
{
int a = num.top();//第二个操作数
num.pop();
int b = num.top();//第一个操作数
num.pop();
char p = op.top();//运算符
op.pop();
int r = 0;//结果
//计算结果
if (p == '+') r = b + a;
if (p == '-') r = b - a;
if (p == '*') r = b * a;
if (p == '/') r = b / a;
num.push(r);//结果入栈
}
int main()
{
string s;//读入表达式
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (isdigit(s[i]))//数字入栈
{
int x = 0, j = i;//计算数字
while (j < s.size() && isdigit(s[j]))
{
x = x * 10 + s[j] - '0';
j++;
}
num.push(x);//数字入栈
i = j - 1;
}
//左括号无优先级,直接入栈
else if (s[i] == '(')//左括号入栈
{
op.push(s[i]);
}
//括号特殊,遇到左括号直接入栈,遇到右括号计算括号里面的
else if (s[i] == ')')//右括号
{
while(op.top() != '(')//一直计算到左括号
eval();
op.pop();//左括号出栈
}
else
{
while (op.size() && h[op.top()] >= h[s[i]])//待入栈运算符优先级低,则先计算
eval();
op.push(s[i]);//操作符入栈
}
}
while (op.size()) eval();//剩余的进行计算
cout << num.top() << endl;//输出结果
return 0;
}
class Solution {
public:
int sum(TreeNode* root, int level) {
if(!root) return 0;
if(!root->left && !root->right) {
return root->val * level;
}
return sum(root->left, level + 1) + sum(root->right, level + 1);
}
int pathSum(TreeNode* root) {
return sum(root, 0);
}
};
构建二叉树的两种情况【根据前序遍历和中序遍历 构造树】【根据后序遍历和中序遍历 构造树】
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
unordered_map<int,int> pos;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
for (int i = 0; i < n; i ++ )
pos[inorder[i]] = i;
return dfs(preorder, inorder, 0, n - 1, 0, n - 1);
}
TreeNode* dfs(vector<int>&pre, vector<int>&in, int pl, int pr, int il, int ir)
{
if (pl > pr) return NULL;
int k = pos[pre[pl]] - il;
TreeNode* root = new TreeNode(pre[pl]);
root->left = dfs(pre, in, pl + 1, pl + k, il, il + k - 1);
root->right = dfs(pre, in, pl + k + 1, pr, il + k + 1, ir);
return root;
}
};
首先我们要清楚:
二叉排序树的特点是
中序遍历(左根右)是有序的
所以如果删除的根节点有左右子树
那么我们为了保证有序
就要把 根节点左子树的最右边 赋值给根节点
因为根节点左子树的最右边是比根节点小中最大的点
只有这样才能保证删除根节点后
左子树比新的根节点都小
右子树比新的根节点都大
#include
using namespace std;
const int INF = 2e9;
struct TreeNode
{
int val;
TreeNode *left, *right;
TreeNode(int _val): val(_val), left(NULL), right(NULL) {}
}*root;
// 插入操作
void insert(TreeNode* &root, int x)
{
/*
1. 递归找到x的待插入的位置
2. 如果x < 当前root就递归到左子树,反之,递归到右子树。
*/
if (!root) root = new TreeNode(x);
// 如果发现数值相同的话就判断一下;
if (root->val == x) return;
else if (x < root->val) insert(root->left, x);
else insert(root->right, x);
}
void remove(TreeNode* &root, int x)
{
/*
1. 待删除的结点只有左子树。立即可推出,左子树上的结点都是小于待删除的结点的,我们只需要把待删除结点删了然后左子树接上待删除结点的父节点就可以了。
2. 待删除的结点只有右子树。立即可推出,右子树上的结点都是大于待删除的结点的,我们只需要把待删除结点删了然后右子树接上待删除结点的父节点就可以了。
3. 待删除的结点既有左子树又有右子树。这个比上两个情况麻烦一点,但也不麻烦,需要读者理解的是,怎么能删除结点后还不改变中序遍历的结果,并且操作代价最小,显而易见,我们根据待删除结点的左子树可以得到最右下角的最后结点满足$
// 如果不存在直接return
if (!root) return;
if (x < root->val) remove(root->left, x);
else if (x > root->val) remove(root->right, x);
else
{
if (!root->left && !root->right) root = NULL;
else if (!root->left) root = root->right;
else if (!root->right) root = root->left;
else
{
auto p = root->left;
while (p->right) p = p->right;
root->val = p->val;
remove(root->left, p->val);
}
}
}
// 输出数值 x 的前驱(前驱定义为现有所有数中小于 x 的最大的数)。
int get_pre(TreeNode* root, int x)
{
if (!root) return -INF;
if (root->val >= x) return get_pre(root->left, x);
else return max(root->val, get_pre(root->right, x));
}
// 输出数值 x 的后继(后继定义为现有所有数中大于 x 的最小的数)。
int get_suc(TreeNode* root, int x)
{
if (!root) return INF;
if (root->val <= x) return get_suc(root->right, x);
else return min(root->val, get_suc(root->left, x));
}
int main()
{
int n;
cin >> n;
while (n--)
{
int t, x;
cin >> t >> x;
if (t == 1) insert(root, x);
else if (t == 2) remove(root, x);
else if (t == 3) cout << get_pre(root, x) << endl;
else cout << get_suc(root, x) << endl;
}
return 0;
}
本题就是中序遍历
只要不是叶子节点
就加左括号然后遍历左边
遍历完右边加右括号
class Solution {
public:
string dfs(TreeNode* root) {
if(!root) return "";
if(!root->left && !root->right) {
return root->val;
}
string ret = "";
ret += '(';
ret += dfs(root->left);
ret += root->val;
ret += dfs(root->right);
ret += ')';
return ret;
}
string expressionTree(TreeNode* root) {
return dfs(root->left) + root->val + dfs(root->right);
}
};
本题就记住哈夫曼树的最简代码如下:
#include
#include
#include
using namespace std;
int main()
{
int n;
scanf("%d", &n);
priority_queue<int, vector<int>, greater<int>> heap;
while (n -- )
{
int x;
scanf("%d", &x);
heap.push(x);
}
int res = 0;
while (heap.size() > 1)
{
int a = heap.top(); heap.pop();
int b = heap.top(); heap.pop();
res += a + b;
heap.push(a + b);
}
printf("%d\n", res);
return 0;
}
可以忽略这个段,下面有
图中所说的合并的次数,本质其实是根节点的深度
所以优先队列的元素是pair
一个记录权值 一个记录深度
题解图中有解释
原题链接
所以优先队列的元素是pair
一个记录权值 一个记录深度
#include
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<LL, int> PLI;
int main()
{
int n, k;
scanf("%d%d", &n, &k);
priority_queue<PLI, vector<PLI>, greater<PLI>> heap;
while (n -- )
{
LL w;
scanf("%lld", &w);
heap.push({w, 0});
}
while ((heap.size() - 1) % (k - 1)) heap.push({0, 0});
LL res = 0;
while (heap.size() > 1)
{
LL s = 0;
int depth = 0;
for (int i = 0; i < k; i ++ )
{
auto t = heap.top();
heap.pop();
s += t.x, depth = max(depth, t.y);
}
heap.push({s, depth + 1});
res += s;
}
printf("%lld\n%d\n", res, heap.top().y);
return 0;
}
原题链接
这就是一个模板
算法原理可以csdn搜一下
#include
#include
#include
using namespace std;
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx;
int d[N];
int q[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
bool topsort()
{
int hh = 0, tt = -1;
for (int i = 1; i <= n; i ++ )
if (!d[i])
q[ ++ tt] = i;
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (-- d[j] == 0)
q[ ++ tt] = j;
}
}
return tt == n - 1;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 0; i < m; i ++ )
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
d[b] ++ ;
}
if (!topsort()) puts("-1");
else
{
for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);
puts("");
}
return 0;
}
原题链接
从1节点出发,每次走最短路径(距离集合的最短路径用d表示)选出最短路径再加到res上
(prim算法和dijkstra算法差不多,只是d的表示含义不同)
#include
#include
#include
using namespace std;
const int N = 510, M = 100010, INF = 0x3f3f3f3f;
int n, m;
int g[N][N], dist[N];
bool st[N];
int prim()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
int res = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
if (dist[t] == INF) return INF;
st[t] = true;
res += dist[t];
for (int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], g[t][j]);
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = min(g[a][b], c);
}
int res = prim();
if (res == INF) puts("impossible");
else printf("%d\n", res);
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1e5 + 10;
int n, m;
int head[N], e[N], ne[N], w[N], idx;
bool st[N];
int dist[N];
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = head[a];
head[a] = idx++;
}
int spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true; //判重数组, 队列中有重复的点没有意义
while (q.size()) {
int t = q.front();
q.pop();
st[t] = false;
for (int i = head[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[t] + w[i]) {
dist[j] = dist[t] + w[i];
if (!st[j]) {
q.push(j);
st[j] = true;
}
}
}
}
if (dist[n] == 0x3f3f3f3f) {
return -1;
}
return dist[n];
}
int main()
{
cin >> n >> m;
memset(head, -1, sizeof head);
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
int t = spfa();
if (t == -1) {
cout << -1 << endl;
}
else {
cout << dist[n] << endl;
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 210, INF = 0x3f3f3f3f;
int n, m, Q;
int d[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &Q);
memset(d, 0x3f, sizeof d);
for (int i = 1; i <= n; i ++ ) d[i][i] = 0;
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
d[a][b] = min(d[a][b], c);
}
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
while (Q -- )
{
int a, b;
scanf("%d%d", &a, &b);
int c = d[a][b];
if (c > INF / 2) puts("impossible");
else printf("%d\n", c);
}
return 0;
}
权值可能为负
所以需要每条路径都走
而不是像dijkstra算法只走一部分
所以spfa算法用普通队列存储即可
并且每个点可能走多次,所以st需要再次false
#include
#include
#include
#include
using namespace std;
const int N = 100010;
int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
int spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
int t = spfa();
if (t == 0x3f3f3f3f) puts("impossible");
else printf("%d\n", t);
return 0;
}
就记住有N个链表头节点
对于原数据可以 (x % N + N) % N;找到合适位置插入到头节点
#include
#include
using namespace std;
const int N = 1e5 + 3; // 取大于1e5的第一个质数,取质数冲突的概率最小 可以百度
//* 开一个槽 h
int h[N], e[N], ne[N], idx; //邻接表
void insert(int x) {
// c++中如果是负数 那他取模也是负的 所以 加N 再 %N 就一定是一个正数
int k = (x % N + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx++;
}
bool find(int x) {
//用上面同样的 Hash函数 讲x映射到 从 0-1e5 之间的数
int k = (x % N + N) % N;
for (int i = h[k]; i != -1; i = ne[i]) {
if (e[i] == x) {
return true;
}
}
return false;
}
int n;
int main() {
cin >> n;
memset(h, -1, sizeof h); //将槽先清空 空指针一般用 -1 来表示
while (n--) {
string op;
int x;
cin >> op >> x;
if (op == "I") {
insert(x);
} else {
if (find(x)) {
puts("Yes");
} else {
puts("No");
}
}
}
return 0;
}
#include
#include
using namespace std;
//开放寻址法一般开 数据范围的 2~3倍, 这样大概率就没有冲突了
const int N = 2e5 + 3; //大于数据范围的第一个质数
const int null = 0x3f3f3f3f; //规定空指针为 null 0x3f3f3f3f
int h[N];
int find(int x) {
int t = (x % N + N) % N;
while (h[t] != null && h[t] != x) {
t++;
if (t == N) {
t = 0;
}
}
return t; //如果这个位置是空的, 则返回的是他应该存储的位置
}
int n;
int main() {
cin >> n;
memset(h, 0x3f, sizeof h); //规定空指针为 0x3f3f3f3f
while (n--) {
string op;
int x;
cin >> op >> x;
if (op == "I") {
h[find(x)] = x;
} else {
if (h[find(x)] == null) {
puts("No");
} else {
puts("Yes");
}
}
}
return 0;
}
由于我们需要从1去找 是否出现在数组中
如果1去遍历一遍数组
2遍历一遍数组
太麻烦
如何一步到位?
其实可以用
哈希思想
把数组出现的数都映射存储到数组中
如何都没有出现
那么一定是大于数组的个数+1的那个值
class Solution {
public:
int findMissMin(vector<int>& nums) {
int n = nums.size();
vector<bool> hash(n + 1);
for (int x: nums)
if (x >= 1 && x <= n)
hash[x] = true;
for (int i = 1; i <= n; i ++ )
if (!hash[i])
return i;
return n + 1;
}
};
KMP是快速帮助 子串A 去匹配 主串B的算法
我们利用next记录
当B和A不匹配的时候,A应该返回B中的哪个位置
所以next应该记录的是B的快速匹配位置
具体逻辑可以搜CSDN
#include
#include
#include
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
char p[N], s[M];
int ne[N];
int main()
{
scanf("%d%s", &n, p + 1);
scanf("%d%s", &m, s + 1);
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == n) printf("%d ", i - n);
}
return 0;
}
#include
#include
#include
using namespace std;
const int N=100020;
int a[N];
int n;
void quick_sort(int l,int r)
{
if(l>=r) return ;
int k=a[l+r>>1],i=l-1,j=r+1;
while(i<j)
{
do i++; while(a[i]<k);
do j--; while(a[j]>k);
if(i<j) swap(a[i],a[j]);
}
quick_sort(l,j);
quick_sort(j+1,r);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
quick_sort(0,n-1);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
#include
#include
using namespace std;
const int N = 100010;
int a[N];
int sum(int a[], int l, int r)//求数组 a[l] ~ a[r] 的和
{
int res = 0;
for(int i = l; i <= r; i++)
res += a[i];
return res;
}
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a,a + n);//排序
int s1, s2;
s1 = sum(a, 0, n/2-1);//s1 的和小
s2 = sum(a, n/2, n - 1);//s2 的和大
cout << n % 2 << " " << s2 - s1;
}
什么是多路归并?
就是三个数组排序到一个数组进行比较
是需要开一个数组的空间的
为了节约空间,我们可以通过三个数组分别用三个指针
指向各自数组,然后判断当前三个元素的大小关系以及进行相应的运算或者应用数据去计算,之后根据三个元素的大小关系进行角标转移
放到本题中
首先我们要理解题意
题意是让我们求三个数组中放到一个数组排序后,出现的最小值到最大值距离最短的是多少
比如
a b c之间满足
最小值a 到 最大值c距离最小
并且之间包含b数组的元素
或者是
b a c也可以
总之就是
最小值和最大值并且中间包含一个与这两个集合不一样的集合元素
的距离值 ✖ 2就是答案
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 100010;
int l, m, n;
int a[N], b[N], c[N];
int main()
{
scanf("%d%d%d", &l, &m, &n);
for (int i = 0; i < l; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < m; i ++ ) scanf("%d", &b[i]);
for (int i = 0; i < n; i ++ ) scanf("%d", &c[i]);
LL res = 1e18;
for (int i = 0, j = 0, k = 0; i < l && j < m && k < n;)
{
int x = a[i], y = b[j], z = c[k];
res = min(res, (LL)max(max(x, y), z) - min(min(x, y), z));
if (x <= y && x <= z) i ++ ;
else if (y <= x && y <= z) j ++ ;
else k ++ ;
}
printf("%lld\n", res * 2);
return 0;
}
class Solution {
public:
int moreThanHalfNum_Solution(vector<int>& nums) {
int cnt = 0, val;
for (auto x: nums) {
if (!cnt) val = x, cnt ++ ;
else if (x == val) cnt ++ ;
else cnt -- ;
}
return val;
}
};
#include
#include
#include
using namespace std;
const int N = 10;
int n;
char str[N], path[N];
bool st[N];
void dfs(int u)
{
if (u == n) cout << path << endl;
else
{
for (int i = 0; i < n; i ++ )
if (!st[i])
{
path[u] = str[i];
st[i] = true;
dfs(u + 1);
st[i] = false;
}
}
}
int main()
{
cin >> str;
n = strlen(str);
dfs(0);
return 0;
}
#include
using namespace std;
const int N = 100;
int g[N][N];
bool l[N*2],ll[N*2],lll[N*2];
int d[N],idx;
int n;
void dfs(int u,int sum)
{
if(u>8)
{
d[++idx] = sum;
}
else
{
for(int i = 1; i <= 8; i++)
{
if(l[i] == false && ll[i+u] == false && lll[i-u+9] == false)
{
l[i] = true;
lll[i-u+9] = true;
ll[i+u] = true;
dfs(u+1,sum*10+i);
l[i] = false;
lll[i-u+9] = false;
ll[i+u] = false;
}
}
}
}
int main()
{
cin >> n;
dfs(1,0);
while(n--)
{
int x;
cin >> x;
cout << d[x] << endl;
}
return 0;
}
高精度计算核心就是
通过数组模拟出草稿纸上的运算过程
具体逻辑可以搜csdn
#include
#include
#include
using namespace std;
int main()
{
string s;
while (cin >> s)
{
reverse(s.begin(), s.end());
cout << s << endl;
}
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
string a, b;
cin >> a >> b;
int res = 0;
for (auto x: a)
for (auto y: b)
res += (x - '0') * (y - '0');
cout << res << endl;
return 0;
}
#include
#include
#include
using namespace std;
int s[6][10];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
while (n -- )
{
int x;
scanf("%d", &x);
for (int i = 0; i < m; i ++ )
{
s[i][x % 10] ++ ;
x /= 10;
}
}
for (int i = 0; i < m; i ++ )
{
int k = 0;
for (int j = 0; j < 10; j ++ )
if (s[i][k] < s[i][j])
k = j;
printf("%d\n", k);
}
return 0;
}
#include
#include
using namespace std;
const int N=110;
int candy[N],bak[N];
int n,count;
bool isequal()
{
for(int i=1;i<n;i++)
if(candy[i]!=candy[i-1])
return false;
return true;
}
void share()
{
memset(bak,0,sizeof(bak));
for(int i=0;i<n;i++)
bak[(i+1)%n]=candy[i]/2;
for(int i=0;i<n;i++)
candy[i]=candy[i]/2+bak[i];
for(int i=0;i<n;i++)
if(candy[i]%2)
candy[i]=candy[i]+1;
}
int main()
{
scanf("%d",&n);
while(n!=0)
{
for(int i=0;i<n;i++) scanf("%d",&candy[i]);
count=0;
while(!isequal())
{
share();
count++;
}
printf("%d %d\n",count,candy[0]);
scanf("%d",&n);
}
}
#include
#include
#include
using namespace std;
const int N = 10010, MOD = 10000;
int a[N];
int main()
{
int p, q, k;
cin >> a[0] >> a[1] >> p >> q >> k;
for (int i = 2; i <= k; i ++ )
a[i] = (p * a[i - 1] + q * a[i - 2]) % MOD;
cout << a[k] % MOD << endl;
return 0;
}
#include
using namespace std;
int main()
{
int n,f[21];
cin>>n;
f[0]=1;
f[1]=1;
for(int i=2;i<=n;i++)f[i]=f[i-1]+f[i-2];
cout<<f[n];
}
整体思路是用BFS暴搜
存在队列中的基本元素是pair
因为数字本身可能会重复出现,而且对于一个字符串交换它两个不同相邻位置得到的新字符串,也可能产生重复,但我们要求的是最少交换次数,因为BFS的性质,保证了可以实现最小,所以可以设置一个map映射组,来存储已经出现过的字符串情况,防止重复对相同组成的字符串再入队处理,以作到剪枝的作用,降低时间复杂度。
这道题进入BFS暴搜前,要做一些基本的判断,很容易就考虑不到,要做好了。
#include
#include
#include
#include
#include
using namespace std;
int n;
int bfs(string start)
{
queue<string> q;
unordered_map<string, int> dist;
dist[start] = 0;
q.push(start);
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < n; i ++ )
if (t.substr(i, 4) == "2012")
return dist[t];
for (int i = 1; i < n; i ++ )
{
string r = t;
swap(r[i], r[i - 1]);
if (!dist.count(r))
{
dist[r] = dist[t] + 1;
q.push(r);
}
}
}
return -1;
}
int main()
{
string start;
cin >> n >> start;
cout << bfs(start) << endl;
return 0;
}
本题的思路由样例入手
根据样例分析出
只要每行有两个元素
那么该行就能推出所有等差数据
同理列也是
所以我们先遍历所有行和列
看哪些有两个元素的
然后根据这样行和列进行填充
填充过程中观察是否新数据使得对应的行或者列
变得大于两个元素,进而可以填充
那么该过程就想到了bfs
bfs队列存储的元素是什么呢?就是所在的行或者列
怎么判断是行还是列呢?
行的范围为(0-n)
列的范围(n,m+n)
#include
#include
#include
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010, M = N * 2;
int n, m;
int row[N], col[N];
int q[M], hh, tt = -1;
bool st[M];
PII ans[N * N];
int top;
int g[N][N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
{
scanf("%d", &g[i][j]);
if (g[i][j])
{
row[i] ++ ;
col[j] ++ ;
}
}
for (int i = 0; i < n; i ++ )
if (row[i] >= 2 && row[i] < m)
{
q[ ++ tt] = i;
st[i] = true;
}
for (int i = 0; i < m; i ++ )
if (col[i] >= 2 && col[i] < n)
{
q[ ++ tt] = i + n;
st[i + n] = true;
}
while (hh <= tt)
{
auto t = q[hh ++ ];
if (t < n) // 行
{
PII p[2];
int cnt = 0;
for (int i = 0; i < m; i ++ )
if (g[t][i])
{
p[cnt ++ ] = {i, g[t][i]};
if (cnt == 2) break;
}
int d = (p[1].y - p[0].y) / (p[1].x - p[0].x);
int a = p[1].y - d * p[1].x;
for (int i = 0; i < m; i ++ )
if (!g[t][i])
{
g[t][i] = a + d * i;
ans[top ++ ] = {t, i};
col[i] ++ ;
if (col[i] >= 2 && col[i] < m && !st[i + n])
{
q[ ++ tt] = i + n;
st[i + n] = true;
}
}
}
else // 列
{
t -= n;
PII p[2];
int cnt = 0;
for (int i = 0; i < n; i ++ )
if (g[i][t])
{
p[cnt ++ ] = {i, g[i][t]};
if (cnt == 2) break;
}
int d = (p[1].y - p[0].y) / (p[1].x - p[0].x);
int a = p[1].y - d * p[1].x;
for (int i = 0; i < n; i ++ )
if (!g[i][t])
{
g[i][t] = a + d * i;
ans[top ++ ] = {i, t};
row[i] ++ ;
if (row[i] >= 2 && row[i] < n && !st[i])
{
q[ ++ tt] = i;
st[i] = true;
}
}
}
}
sort(ans, ans + top);
for (int i = 0; i < top; i ++ )
{
auto& p = ans[i];
printf("%d %d %d\n", p.x + 1, p.y + 1, g[p.x][p.y]);
}
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
string s;
getline(cin, s);
for (int i = 0; i < s.size(); i ++ )
if (!i || s[i - 1] == ' ')
cout << (char)toupper(s[i]);
else
cout << s[i];
return 0;
}
#include
#include
#include
#include
using namespace std;
const int N = 10010;
int n;
string logs[N];
int main()
{
while (getline(cin, logs[n]))
if (logs[n].size()) n ++ ;
else break;
sort(logs, logs + n, [](string& a, string &b) {
stringstream ssina(a), ssinb(b);
string sa[4], sb[4];
for (int i = 0; i < 4; i ++ )
{
ssina >> sa[i];
ssinb >> sb[i];
}
if (sa[3] == sb[3]) return sa[1] + sa[2] < sb[1] + sb[2];
double ta, tb;
sscanf(sa[3].c_str(), "%lf(s)", &ta);
sscanf(sb[3].c_str(), "%lf(s)", &tb);
return ta < tb;
});
for (int i = 0; i < n; i ++ )
cout << logs[i] << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long LL;
int main()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i ++ )
if (isdigit(s[i]))
{
LL x = 0;
while (i < s.size() && isdigit(s[i]))
{
x = x * 10 + s[i] - '0';
if (x > INT_MAX)
{
puts("-1");
return 0;
}
i ++ ;
}
cout << x << endl;
return 0;
}
puts("-1");
return 0;
}
本题由于第三次图形需要知道 第二层的图形
所以需要递归
#include
#include
#include
#include
using namespace std;
int n;
vector<string> p;
vector<string> g(int k)
{
if (k == 1) return p;
auto s = g(k - 1);
int m = s.size();
vector<string> res(n * m);
for (int i = 0; i < n * m; i ++ )
res[i] = string(n * m, ' ');
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
if (p[i][j] != ' ')
for (int x = 0; x < m; x ++ )
for (int y = 0; y < m; y ++ )
res[i * m + x][j * m + y] = s[x][y];
return res;
}
int main()
{
while (cin >> n, n)
{
p.clear();
getchar(); // 读掉n后的回车
for (int i = 0; i < n; i ++ )
{
string line;
getline(cin, line);
p.push_back(line);
}
int k;
cin >> k;
auto res = g(k);
for (auto& s: res) cout << s << endl;
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1010;
int n, m;
int f[N][N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
{
int v, w;
scanf("%d%d", &v, &w);
for (int j = 0; j <= m; j ++ )
{
f[i][j] = f[i - 1][j];
if (j >= v)
f[i][j] = max(f[i][j], f[i - 1][j - v] + w);
}
}
printf("%d\n", f[n][m]);
return 0;
}
#include
using namespace std;
const int N = 50;
int f[N][N];
int a[N];
int n;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
f[0][0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= 40; j++)
{
f[i][j] = f[i-1][j];
if(a[i]<=j)
{
f[i][j] = f[i][j] + f[i-1][j-a[i]];
}
}
}
cout << f[n][40];
return 0;
}
本题中如果用这种做法的话会爆内存
#include
using namespace std;
typedef long long LL;
const int N = 1e6+10, mod = 1e9;
LL v[25], f[25][N]; //v[]:存储 2 的 i 次幂,即 2^i
void init(){ //预处理出 2 的 0 次幂到 20 次幂
v[0] = 1;
for(int i = 1;i <= 20;++i) v[i] = v[i - 1] * 2;
}
void solve(){
int n;
cin >> n;
init();
for(int i = 0;i <= 20;++i){
for(int j = 0;j <= n;++j){
if(!i || !j){ //状态为 f[i][0] 和 f[0][j] 时,将其初始化为 1
f[i][j] = 1;
continue;
}
if(j < v[i]) f[i][j] = f[i - 1][j]; //当 2^i > j 时,f[i][j]中只有一个集合(有0个 2^i 的集合)
else f[i][j] = (f[i - 1][j] + f[i][j - v[i]]) % mod; //状态转移方程
}
}
cout << f[20][n];
}
int main(){
solve();
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1000010, MOD = 1e9;
int n;
int f[N];
int main()
{
scanf("%d", &n);
f[0] = 1;
for (int i = 1; i <= n; i *= 2)
for (int j = i; j <= n; j ++ )
f[j] = (f[j] + f[j - i]) % MOD;
cout << f[n] << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
const int N = 1010;
vector<int> F[N];
vector<int> mul(vector<int>& A, int b)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
return C;
}
int main()
{
int n;
F[0] = {1};
for (int i = 1; i <= 1000; i ++ ) F[i] = mul(F[i - 1], i);
while (cin >> n)
{
for (int i = F[n].size() - 1; i >= 0; i -- )
cout << F[n][i];
cout << endl;
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int add(vector<int>& A, vector<int>& B)
{
int res = 0;
for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
{
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
t /= 10;
res += t;
}
return res;
}
int main()
{
string a, b;
while (cin >> a >> b, a != "0" || b != "0")
{
vector<int> A, B;
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
int res = add(A, B);
if (!res) puts("No carry operation.");
else if (res == 1) puts("1 carry operation.");
else printf("%d carry operations.\n", res);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
vector<int> add(vector<int>& A, vector<int>& B)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
{
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
return C;
}
int main()
{
vector<int> A{0};
string b;
while (cin >> b, b != "0")
{
vector<int> B;
for (int i = b.size() - 1; i >= 0; i -- )
B.push_back(b[i] - '0');
A = add(A, B);
}
while (A.size() > 1 && !A.back()) A.pop_back();
for (int i = A.size() - 1; i >= 0; i -- )
cout << A[i];
cout << endl;
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
int n;
while (cin >> n)
{
int res = 0;
for (int i = 2; i * i <= n; i ++ )
if (n % i == 0)
{
while (n % i == 0)
{
n /= i;
res ++ ;
}
}
if (n > 1) res ++ ;
cout << res << endl;
}
return 0;
}
#include
using namespace std;
int n, x;
int main()
{
cin >> n;
while (n -- )
{
cin >> x;
int res = 0;
for (int i = 1; i <= x / i; i ++)
if (x % i == 0)
{
res ++ ;
if (x / i != i) res ++ ;
}
cout << res << '\n';
}
return 0;
}
末尾的0 就表示 因数中有多少个10
那么也就是有多少个因数2 和 5
由于因数2的个数一定大于5的个数
所以就看有多少个因数5就可以了
#include
#include
#include
using namespace std;
int main()
{
int n;
cin >> n;
int res = 0;
while (n / 5) res += n / 5, n /= 5;
cout << res << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
vector<vector<int>> get_ds(int n)
{
vector<vector<int>> res;
for (int i = 2; i * i <= n; i ++ )
if (n % i == 0)
{
int s = 0;
while (n % i == 0) n /= i, s ++ ;
res.push_back({i, s});
}
if (n > 1) res.push_back({n, 1});
return res;
}
int get_p(int n, int p)
{
int res = 0;
while (n / p) res += n / p, n /= p;
return res;
}
int main()
{
int n, m;
cin >> n >> m;
auto ds = get_ds(m);
int res = 1e8;
for (int i = 0; i < ds.size(); i ++ )
{
int p = ds[i][0], s = ds[i][1];
res = min(res, (get_p(n, p) / s));
}
cout << res << endl;
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
int n;
cin >> n;
int res = 0;
for (int i = 1; i <= n; i ++ )
{
if (i % 7 == 0 || to_string(i).find('7') != -1)
continue;
res += i * i;
}
cout << res << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110;
int n;
int w[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> w[i];
for (int i = 0; i < n; i ++ )
if (!i)
{
if (n == 1 || w[i] != w[i + 1]) cout << i << ' ';
}
else if (i == n - 1)
{
if (w[i] != w[i - 1]) cout << i << ' ';
}
else
{
if (w[i] > w[i - 1] && w[i] > w[i + 1] ||
w[i] < w[i - 1] && w[i] < w[i + 1])
cout << i << ' ';
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110;
int n;
int a[N];
// 欧几里得算法(辗转相除法)
int gcd(int a, int b) {
return b? gcd(b, a % b): a;
}
int main() {
while (cin >> n && n) {
memset(a, 0, sizeof(a));
int cnt = 0;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (a[i] < a[j] && gcd(a[i], a[j]) == 1) {
cnt++;
}
}
}
cout << cnt << endl;
}
return 0;
}
include <iostream>
#include
#include
using namespace std;
int main()
{
double n, k;
while (cin >> n >> k)
{
double sum = n, house = 200;
bool flag = false;
for (int i = 1; i <= 21; i ++ )
{
if (sum >= house)
{
cout << i << endl;
flag = true;
break;
}
sum += n;
house *= 1 + k / 100;
}
if (!flag) puts("Impossible");
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
int T;
cin >> T;
while (T -- )
{
int n;
cin >> n;
int res = 0;
for (int i = 1; i * i * i <= n; i ++ )
{
int x = i * i * i;
int r = sqrt(x);
if (r * r == x)
res ++ ;
}
cout << res << endl;
}
return 0;
}
本题的思路是:
把a右移1位,如果超界,&65535(也就是保留16位)
然后让a + (a未移动的值右移15位的值)
得到的就是循环移动的值了
#include
using namespace std;
int main()
{
int a,b;
while(cin >> a >> b)
{
bool flag = false;
for(int i = 0; i < 16;i++)
{
int t = a;
a = (a << 1)&65535;
a = a + (t>>15);
if(a==b)
{
cout << "YES" << endl;
flag = true;
}
}
if(flag==false)
{
cout << "NO" << endl;
}
}
return 0;
}
#include
#include
#include
using namespace std;
int main()
{
unsigned int n;
while (cin >> n)
{
string res;
if (!n) res = "0";
while (n) res += to_string(n & 1), n >>= 1;
reverse(res.begin(), res.end());
cout << res << endl;
}
return 0;
}
这道题就是找规律
#include
#include
#include
#include
using namespace std;
const int N = 10;
int n;
vector<vector<int>> rotate(vector<vector<int>> a)
{
auto res = a;
for (int i = 0; i < n; i ++ )
for (int j = 0, k = n - 1; j < n; j ++, k -- )
res[i][j] = a[k][i];
return res;
}
int main()
{
cin >> n;
vector<vector<int>> a(n, vector<int>(n));
auto b = a;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
cin >> a[i][j];
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
cin >> b[i][j];
for (int i = 0; i < 4; i ++ )
{
if (a == b)
{
cout << i * 90 << endl;
return 0;
}
a = rotate(a);
}
puts("-1");
return 0;
}
两个矩阵a,b相乘得到一个新的矩阵c,新矩阵的第i行第j列的元素是a的第i行和b的第j列的对应元素相乘的求和。
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp[i][j]+=a[i][k]*b[k][j];
求矩阵的k次方
注意:1次方就是 矩阵乘单位矩阵
#include
#include
#include
#include
using namespace std;
const int N=15;
int n,k;
int w[N][N];
// 将矩阵a和b相乘,结果存放到c中。
void mul(int c[][N],int a[][N],int b[][N]){
static int tmp[N][N];
memset(tmp,0,sizeof tmp);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp[i][j]+=a[i][k]*b[k][j];
memcpy(c,tmp,sizeof tmp);
}
int main(){
cin>>n>>k;
// 读入原始矩阵
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>> w[i][j];
// 将res初始化为单位矩阵
int res[N][N]={0};
for(int i=0;i<n;i++) res[i][i]=1;
while(k--) mul(res,res,w);
// 输出结果矩阵
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
cout<<res[i][j]<<" ";
cout<<endl;
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 5;
int n;
int g[N][N];
void rotate(int x, int y, int m)
{
int w[N][N];
memcpy(w, g, sizeof g);
for (int i = 0; i < m; i ++ )
for (int j = 0, k = m - 1; j < m; j ++, k -- )
w[i][j] = g[x + k][y + i];
for (int i = 0; i < m; i ++ )
for (int j = 0; j < m; j ++ )
g[x + i][y + j] = w[i][j];
}
int main()
{
for (int i = 0; i < 5; i ++ )
for (int j = 0; j < 5; j ++ )
cin >> g[i][j];
int a, b, x, y;
cin >> a >> b >> x >> y;
x --, y -- ;
if (a == 1) rotate(x, y, b);
else
{
for (int i = 0; i < 3; i ++ )
rotate(x, y, b);
}
for (int i = 0; i < 5; i ++ )
{
for (int j = 0; j < 5; j ++ )
cout << g[i][j] << ' ';
cout << endl;
}
return 0;
}
#include
#include
#include
#include
using namespace std;
const double PI = acos(-1);
int main()
{
int T;
cin >> T;
while (T -- )
{
double x0, y0, z0, x1, y1, z1;
cin >> x0 >> y0 >> z0 >> x1 >> y1 >> z1;
double dx = x0 - x1;
double dy = y0 - y1;
double dz = z0 - z1;
double r = sqrt(dx * dx + dy * dy + dz * dz);
double v = 4.0 / 3 * PI * r * r * r;
printf("%.2lf %.2lf\n", r, v);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
class CPoint
{
public:
double x, y;
CPoint(){}
CPoint(double _x, double _y): x(_x), y(_y) {}
double operator- (const CPoint& t) const
{
double dx = x - t.x;
double dy = y - t.y;
return sqrt(dx * dx + dy * dy);
}
};
int main()
{
int T;
cin >> T;
while (T -- )
{
CPoint a, b;
cin >> a.x >> a.y >> b.x >> b.y;
printf("%.2lf\n", a - b);
}
return 0;
}
#include
#include
#include
#include
using namespace std;
struct CPoint
{
double x, y;
double operator- (const CPoint& t) const
{
double dx = x - t.x;
double dy = y - t.y;
return sqrt(dx * dx + dy * dy);
}
};
struct CTriangle
{
CPoint a, b, c;
bool check()
{
double d[3] = {a - b, b - c, a - c};
sort(d, d + 3);
return fabs(d[0] * d[0] + d[1] * d[1] - d[2] * d[2]) < 1e-8;
}
double get_len()
{
return (a - b) + (b - c) + (a - c);
}
};
int main()
{
int T;
cin >> T;
while (T -- )
{
CTriangle t;
cin >> t.a.x >> t.a.y >> t.b.x >> t.b.y >> t.c.x >> t.c.y;
if (t.check()) puts("Yes");
else puts("No");
printf("%.2lf\n", t.get_len());
}
return 0;
}
#include
using namespace std;
const int N = 1e6 + 10;
int a[N], b[N];
int c[N];
int n;
unordered_map<int, int> st;
int main()
{
string x;
cin >> x;
n = x.size();
for(int i = 1; i <= n; i ++ ){
a[i] = a[i - 1], b[i] = b[i - 1];
if(x[i - 1] == '1') a[i] ++ ;
else b[i] ++ ;
}
int res = 0;
st[0] = 0; //初始化哈希表头, 将从0开始, 到0结束的子串记为0
for(int i = 1; i <= n; i ++ ){
c[i] = a[i] - b[i];
if(st.count(c[i]) != 0) res = max(res, a[i] - a[st[c[i]]]);
else st[c[i]] = i;
}
printf("%d", res * 2);
return 0;
}
#include
#include
#include
using namespace std;
int check(int x,int y)
{
return x*2-(x%2);
}
int main()
{
int x,y,n;
cin>>n;
while(n--)
{
cin>>x>>y;
if(x==y)cout<<check(x,y)<<endl;
else if(x==y+2)cout<<check(x-2,y)+2<<endl;
else puts("No Number");
}
return 0;
}
推等差公式
#include
using namespace std;
int main()
{
int n,x,c=0;
cin>>n;
while(n--){
cin>>x;
c=(abs(x)+1)*3*x/2;//要考虑负数情况,所以一开始要设绝对值
cout<<c<<endl;
}
}
#include
#include
#include
using namespace std;
int main()
{
int T;
cin >> T;
while (T -- )
{
double h;
int n;
cin >> h >> n;
double s = h;
for (int i = 0; i < n - 1; i ++ )
{
s += h;
h /= 2;
}
printf("%.2lf\n", s);
}
return 0;
}
求城市1到所属阵营城市的最短路径,记录在dist1[]中
求城市2到所属阵营城市的最短路径,记录在dist2[]中
遍历所有边,边的两端的城市i、j分别属于阵营1、2, 该边的权重为w
那么本题可以等价于求解:
min(w+dist[i]+dist[j])
#include
#include
#include
using namespace std;
const int N=610,M=20010,INF=0x3f3f3f3f;
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int q[N],dist1[N],dist2[N];
bool st[N];
int team[N];
void add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void spfa(int start,int dist[]){
int hh=0,tt=1;
q[0]=start;
memset(dist,0x3f,sizeof dist1);
dist[start]=0;
while(hh!=tt){
// 队头元素出队
int t=q[hh++];
if(hh==N) hh=0; // 循环队列
st[t]=false;
// 遍历该元素的所有邻接点
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(team[j]!=start)continue; // 如果是不同阵营的则跳过
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i]; // 更新,入队
if(!st[j]){
q[tt++]=j;
if(tt==N) tt=0; // 循环队列
st[j]=true;
}
}
}
}
}
int main(){
while(scanf("%d",&n),n){
scanf("%d",&m);
memset(h,-1,sizeof h),idx=0;
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c); // 无向图,添加双向边
}
for(int i=1;i<=n;i++) scanf("%d",&team[i]); // 输入所属的团队
spfa(1,dist1);
spfa(2,dist2);
int res=INF;
for(int i=0;i<idx;i++){
int a=e[i^1],b=e[i];// 方向相反的一对边
if(team[a]==1 && team[b]==2) // 如果该边连接的两个城市属于不同阵营,则可以更新边
res=min(res,dist1[a]+w[i]+dist2[b]);
}
if(res==INF) puts("-1");
else cout<<res<<endl;
}
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110, MOD = 100000, INF = 0x3f3f3f3f;
int n, m;
int p[N];
int d[N][N];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++ ) p[i] = i;
memset(d, 0x3f, sizeof d);
for (int i = 0; i < n; i ++ ) d[i][i] = 0;
for (int i = 0, len = 1; i < m; i ++, len = len * 2 % MOD)
{
int a, b;
cin >> a >> b;
if (find(a) != find(b))
{
p[find(a)] = find(b);
d[a][b] = d[b][a] = len;
}
}
for (int k = 0; k < n; k ++ )
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
for (int i = 1; i < n; i ++ )
if (d[0][i] == INF) puts("-1");
else cout << d[0][i] % MOD << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 55, M = N * N / 2, INF = 0x3f3f3f3f;
int n, m, Q;
int g[N][N], d[N][N];
struct Edge
{
int a, b;
}e[M];
void floyd()
{
memcpy(d, g, sizeof d);
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n >> m >> Q;
memset(g, 0x3f, sizeof g);
for (int i = 0; i < n; i ++ ) g[i][i] = 0;
for (int i = 1; i <= m; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
e[i] = {a, b};
g[a][b] = g[b][a] = c;
}
floyd();
printf("%d\n", d[1][n]);
while (Q -- )
{
int t;
cin >> t;
int a = e[t].a, b = e[t].b;
g[a][b] = g[b][a] = INF;
}
floyd();
if (d[1][n] == INF) puts("-1");
else cout << d[1][n] << endl;
}
return 0;
}
2.接着n1||m1时,但棋子走出去后,显然没有回头的路,答案应该是N
3.接着是n%2==0时,棋子可以先一直走到底,再把最后一行遍历完,再是倒数第二行,倒数第三…可以发现,棋子从倒数第一行开始的转向分别是右左右左右左右左…只要最后是向左,就可以遍历完,即n为偶数,答案为Y
示意图:
1 2 3
4 5 6
7 8 9
10 11 12
顺序依次为:1 4 7 10 11 12 9 8 5 6 3 2 1
4.然后是m%2==0时,棋子也是先走到底,再把第二列除去第一行的棋子遍历完,接着是第三,第四,第五列(都不遍历第一行)…最后再把第一行遍历了,即可到达终点,答案为Y
示意图:
1 2 3 4
5 6 7 8
9 10 11 12
顺序依次为:1 5 9 10 6 7 11 12 8 4 3 2 1
5.最后剩下的就是无解情况,答案为N
#include
using namespace std;
typedef long long ll;
const ll N=1e5+1e4,M=1e3+1e2;
const ll Maxn=0x3ffffff,Minm=-0x3ffffff;
ll n,m;
signed main()
{
while(cin>>n>>m)
{
if(n==1&&m==1)cout<<"Y";//情况1
else if(n==1||m==1)cout<<"N";//情况2
else if(n%2==0||m%2==0)cout<<"Y";//情况3,4
else cout<<"N";//情况5
cout<<"\n";
}
}
#include
#include
#include
#include
using namespace std;
int main()
{
string str;
while (cin >> str)
{
map<string, int> hash;
for (int i = 0; i < str.size(); i ++ )
{
string s;
for (int j = i; j < str.size(); j ++ )
{
s += str[j];
hash[s] ++ ;
}
}
for (auto& [k, v]: hash)
if (v > 1)
cout << k << ' ' << v << endl;
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
int n, m;
cin >> n;
unordered_set<int> S;
while (n -- )
{
int x;
cin >> x;
S.insert(x);
}
cin >> m;
while (m -- )
{
int x;
cin >> x;
if (S.count(x)) puts("YES");
else puts("NO");
}
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
string str;
getline(cin, str);
map<string, int> hash;
for (int i = 0; i < str.size(); i ++ )
{
if (isalpha(str[i]))
{
int j = i;
string word;
while (j < str.size() && isalpha(str[j]))
word += tolower(str[j ++ ]);
hash[word] ++ ;
i = j;
}
}
for (auto& [k, v]: hash)
cout << k << ':' << v << endl;
return 0;
}
#include
using namespace std;
const int N = 110, INF = 0x3f3f3f3f;
int n, m, k, a[N][N], s[N][N], res = INF;
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++) cin >> a[i][j];
}
//预处理前缀和
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
//枚举每个矩形
for(int a = 1; a <= n; a ++)
{
for(int b = 1; b <= m; b ++)
{
for(int c = 1; c <= n; c ++)
{
for(int d = 1; d <= m; d ++)
{
int ts = s[c][d] - s[c][b - 1] - s[a - 1][d] + s[a - 1] [b - 1]; //矩形内数字和
int tc = (d - b + 1) * (c - a + 1); //矩形面积
if(ts >= k) res = min(res, tc); //如果数字和大于等于k更新答案
}
}
}
}
if(res == INF) cout << -1 << endl;
else cout << res << endl;
return 0;
}
#include
using namespace std;
const int N = 110, INF = 0x3f3f3f3f;
int n, m, k, res = INF;
int g[N][N], s[N][N];
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++) cin >> g[i][j];
}
//s[j][i]表示第i列的前缀和数组
for(int j = 1; j <= m; j ++)
{
for(int i = 1; i <= n; i ++) s[j][i] = s[j][i - 1] + g[i][j];
}
for(int i = 1; i <= n; i ++)
{
for(int j = i; j <= n; j ++)
{
for(int l = 1, r = 1, sum = 0; r <= m; r ++) //双指针
{
sum += (s[r][j] - s[r][i - 1]);
while(sum - (s[l][j] - s[l][i - 1]) >= k)
{
sum -= (s[l][j] - s[l][i - 1]);
l ++;
}
if(sum >= k)res = min(res, (r - l + 1) * (j - i + 1));
}
}
}
if(res == INF) puts("-1");
else cout << res << endl;
return 0;
}
这道题目实际上就是求一串数字中,某一段数字和,使其最大
因此,我们可以使用dp来完成
令:dp[i]为以a[i]结尾的最大序列和
则dp[i]可以为 以a[i-1]结尾的最大序列和加上a[i] 与 a[i]中的最大值
即该题的动态转移方程式可以为:dp[i]=max(dp[i-1]+a[i],dp[i]);
#include
using namespace std;
typedef long long ll;
const ll N=1e5+1e6;
const ll Min=-0x3ffffff;//负∞
ll n,ans=Min;// 【注】:本题涉及到负数,为保证后面的ans=max(ans,dp[i]),ans一开始因赋值为负∞
ll dp[N],a[N];
signed main()
{
cin>>n;
for(ll i=1;i<=n;i++)cin>>a[i],dp[i]=a[i];
for(ll i=2;i<=n;i++)dp[i]=max(dp[i],dp[i-1]+a[i]);//动态转移方程式
for(ll i=1;i<=n;i++)ans=max(ans,dp[i]);
cout<<ans;
}
#include
using namespace std;
const int N = 55, INF = 0x3f3f3f3f;
//f[i]表示以第i个数字结尾并且是前一个数字上升得到的a[i]
//g[i]表示以第i个数字结尾并且是前一个数字下降得到的a[i]
//集合划分:【只有一个a[i]】【其他:倒数第二个元素是第j个数字并且需要是下降得到a[j]:g[j] + 1】
//状态计算:f[i] = max(f[i], g[j] + 1);
int f[N], g[N];
int n, a[N], res = -INF;
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++)
{
f[i] = g[i] = 1;
for(int j = 1; j < i; j ++)
{
if(a[j] > a[i]) f[i] = max(f[i], g[j] + 1);
if(a[j] < a[i]) g[i] = max(g[i], f[j] + 1);
}
res = max(res, max(f[i], g[i]));
}
cout << res << endl;
return 0;
}
#include
using namespace std;
const int N=100010;
int p[N];//定义多个集合
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
/*
经上述可以发现,每个集合中只有祖宗节点的p[x]值等于他自己,即:
p[x]=x;
*/
return p[x];
//找到了便返回祖宗节点的值
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
char op[2];
int a,b;
scanf("%s%d%d",op,&a,&b);
if(*op=='M') p[find(a)]=find(b);//集合合并操作
else
if(find(a)==find(b))
//如果祖宗节点一样,就输出yes
printf("Yes\n");
else
printf("No\n");
}
return 0;
}