【无标题】

必须说明的是set关联式容器。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。
begin()    ,返回set容器的第一个元素

end()      ,返回set容器的最后一个元素

clear()    ,删除set容器中的所有的元素

empty()    ,判断set容器是否为空

max_size()   ,返回set容器可能包含的元素最大个数

size()      ,返回当前set容器中的元素个数

rbegin     ,返回的值和end()相同

rend()     ,返回的值和rbegin()相同

满二叉树

如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

满二叉树示意图
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image.png&pos_id=img-Lkp8Brpm-1698454585300
在这里插入图片描述

图 2 满二叉树示意图

如图 2 所示就是一棵满二叉树。

满二叉树除了满足普通二叉树的性质,还具有以下性质:
满二叉树中第 i 层的节点数为 2n-1 个。
深度为 k 的满二叉树必有 2k-1 个节点 ,叶子数为 2k-1。
满二叉树中不存在度为 1 的节点,每一个分支点中都两棵深度相同的子树,且叶子节点都在最底层。
具有 n 个节点的满二叉树的深度为 log2(n+1)。
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image-1.png&pos_id=img-RouL2xbF-1698454585302
在这里插入图片描述

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image-1.png&pos_id=img-6QfvPjLd-1698454585303在这里插入图片描述

pai运算
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image-2.png&pos_id=img-vFpAI9bH-1698454585303在这里插入图片描述

##E题 exgcd
https://www.cnblogs.com/juruo-zzt/p/exgcd.html

void solve()
{
    ll n, m, x;  
    cin >> n >> m >> x;
    if(!x)
    {
        cout << 0 << '\n';
        return;
    }
    x = n - x;  
    vector<ll> a(m + 1);
    for(int i = 1; i <= m; i++) cin >> a[i];
    ll y = 0;
    for(int i = 1; i <= m; i++) y = (y + a[i]) % n;
    ll s = 0;
    ll ans = 1e18;
    for(int i = 1; i <= m; i++)
    {
        s = (s + a[i]) % n; //逐步sum
        ll z = (x - s) % n; //原始值减去s
        z = (z % n + n) % n;
        ll t1, t2;
        ll d = exgcd(y, n, t1, t2); //sum 和 要求n的最大公约数  // 如果为 n 
        // cout << y << ' ' << n << ' ' << t1 << ' ' << t2 << '\n';
        d = abs(d);
        if(z % d == 0)
        {
            t1 *= z / d;
            ll t = n / d;
            t1 = (t1 % t + t) % t;
            ans = min(ans, t1 * m + i);
        }
    }
    if(ans == 1e18) ans = -1;
    cout << ans << '\n';
}

exgcd
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image-3.png&pos_id=img-x49ByRpT-1698454585304在这里插入图片描述

gcd求最大公约数

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= (a / b) *x;
    return d;
}

https://blog.csdn.net/qq_49593247/article/details/125588288 !!!例题
//代码实现
1ll<<60 表示将数字 1 左移 60 位。在 C++ 中,后缀 ll 表示将数字字面量解释为 long long 类型,而 << 运算符表示左移操作。这个表达式的结果是一个非常大的整数,即 2 的 60 次方。

0x3f3f3f3f 是一个十六进制常量,表示一个特定的整数值。该值在很多算法和竞赛中经常用于初始化答案或作为特殊标志。这个数值在二进制中表示为 0011 1111 0011 1111 0011 1111 0011 1111,为一个十进制数值 1061109567。

这两个常量的区别:

1ll<<60 表示一个非常大的整数,通常用于表示一个超出常规范围的计数或计算结果。
0x3f3f3f3f 是一个固定的整数常量,通常用于初始化答案或标记特殊值。在某些上下文中,它被用作初始最小值或无效值。

符号 ~ 是取反运算符(bitwise not operator)。
在这种情况下,~ret 是对 ret 进行按位取反的操作。如果 ret 的值为 -1,则取反后得到 0,否则得到一个非零的值。通过 if(~ret) 来检查 ret 是否为 -1 的目的是判断 solve 函数是否返回了有效的解。

在 C++ 中,~ 运算符将整数的每个位取反,包括符号位。因此,当 ret 的值为 -1 时,取反后的结果为 0。而其他任何非零整数都会被取反为一个非零的负数。
https://blog.csdn.net/fx677588/article/details/70767446 哈夫曼编码

floyd 算法 最短路径

https://blog.csdn.net/qq_35644234/article/details/60875818
两个矩阵 一个记录前继 一个记录路径长度
Floyd算法是如何工作的: 1.每次都会选择一个中介点,然后,遍历整个矩阵,查找需要更新的值 即 a[i][k] + a[k][j] < a[i][j]

int dist[VertexMax][VertexMax];
int path[VertexMax][VertexMax];

void ShortestPath_Floyd(MGraph G)
{
    int i, j, k;
    // 初始化部分
    for (i = 0; i < G.vexnum; i++)
    {
        for (j = 0; j < G.vexnum; j++)
        {
            dist[i][j] = G.AdjMatrix[i][j];

            if (dist[i][j] != MaxInt)
            {
                path[i][j] = j; // 存入后继
            }
            else
                path[i][j] = -1;
        }
    }

    // 算法核心部分
    for (k = 0; k < G.vexnum; k++) // 拿出每个顶点作为遍历条件
        for (i = 0; i < G.vexnum; i++)
            for (j = 0; j < G.vexnum; j++)
            {
                if (dist[i][j] > dist[i][k] + dist[k][j])
                {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    path[i][j] = path[i][k]; // 存入后继 //分两段 要标记中间k
                }
            }
}

找中间点 每一个路径都便利

void dijsta()
{
    for (i = 1; i < n; i++)
    {
        dis[i] = a[0][i];
        if (a[0][i] != INF)
            p[i] = 0;
        else
            p[i] = -1; // 没有前的条件
    }
    // dijkstra 核心在于每一次在dis里面找最小的, 以这个节点来更新
    for (i = 1; i < n; i++)
    {
        int temp = INF, t = u;
        for (k = 1; k < n; k++)
        {
            if (dis[k] < temp && !flag[k]) // 不止要满足这个dis最小,同时看他还在不在节点里了
            {
                temp = dis[k];
                t = k;
            }
        }
            if (t == u)
                retrun; // 找不到更小的了
        
            for (j = 1; j < n; j++)
            {
                if (dis[j] > dis[t] + dis[t][j] && !flag[j])
                {
                    dis[j] = dis[t] + dis[t][j];
                    p[j] = t;
                }
            }
    
    }

维护从一点到另一点

7-3 城市间紧急救援

路径条数 根据最短路径 到每一点的最短路径条数 dod数组依次叠加, 长度相同的 叠加 更小的直接覆盖

 #include <iostream>
#include <algorithm>
#include <stack>
#define INF 1e9
using namespace std;
int visited[550], num[550], a[550][550], p[550], dis[550], mon[550], dod[550];
int N, M, S, D;
stack<int> st;
int main()
{
    void Dijska();
    int i, j, x, y, ss;
    cin >> N >> M >> S >> D;
    for (i = 0; i < N; i++)
        cin >> num[i];
    for (i = 0; i < N;i++)
    {
        for (j = 0; j < N; j++)
            a[i][j] = INF;
    }
        for (i = 0; i < M; i++)
        {
            cin >> x >> y >> ss;
            a[x][y] = ss;
            a[y][x] = ss;
        }
    Dijska();
    i = D;
    st.push(i);
    while(p[i] != -1)
    {
            st.push(p[i]);
            i = p[i];
    }
    cout << dod[D] << ' '<< mon[D] << endl;
    int flag = 0;
    while(!st.empty())
    {
    if(!flag)
    {
            cout << st.top();
            flag = 1;
    }
    else
        cout << ' ' << st.top();
    st.pop();
    }
    return 0;
}
void Dijska()
{
    int i, j, c, t;
    for (i = 0; i < N; i++)
    {
        visited[i] = 0;
        mon[i] = 0;
        dis[i] = a[S][i];
        if (dis[i] == INF)
            p[i] = -1;
        else
        {
            dod[i] = 1; // 条数
            p[i] = S;
            if(i != S)
            mon[i] = num[S] + num[i];
            else
            mon[i] = num[i];
        }
    }
    visited[S] = 1;
    dis[S] = 0;
    for (i = 0; i < N; i++)
    {
        int temp = INF;
        c = S;
        for (t = 0; t < N; t++)
        {
        if (temp > dis[t] && !visited[t])
        {
            c = t;
            temp = dis[t];
        }
        }
        if (c == S)
        {
            return;
        }
        visited[c] = 1;
        for (j = 0; j < N; j++)
        {
        if (dis[j] > dis[c] + a[c][j] && !visited[j]) 
        {
            dis[j] = dis[c] + a[c][j];
            p[j] = c;
            dod[j] = dod[c];
            mon[j] = mon[c] + num[j];
        }
            else if(dis[j] == dis[c] + a[c][j] && !visited[j])
            {
            dod[j] += dod[c]; //路径长度相同 添加当前dod
            if (mon[j] < mon[c] + num[j]) 
            {
                mon[j] = mon[c] + num[j];
                p[j] = c;
            }
            }
        }
    }
}

pta 公路村村通

pair

使用带有参数的构造函数初始化:
cpp
std::pair<int, std::string> myPair(10, “Hello”); // 使用整数10和字符串"Hello"进行初始化
使用make_pair函数进行初始化:
cpp
std::pair<int, std::string> myPair = std::make_pair(20, “World”); // 使用整数20和字符串"World"进行初始化
或者使用C++17中的类模板参数推导功能简化为:

cpp
auto myPair = std::make_pair(20, “World”);
直接使用花括号进行列表初始化:
cpp
std::pair<int, std::string> myPair = {30, “Foo”}; // 使用整数30和字符串"Foo"进行初始化
或者使用C++17中的类模板参数推导功能简化为:

cpp
auto myPair = std::pair(30, “Foo”);
调用 ceil(x) 函数来对变量 x 进行向上取整操作。
下面是一个示例代码:

向上取整

#include <iostream>
#include <cmath>

int main() {
double x = 2.3;
double result = ceil(x);
std::cout << "向上取整后的结果为: " << result << std::endl;
return 0;
}

ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);

一.sync_with_stdio
这个函数是一个“是否兼容stdio”的开关,C++为了兼容C,保证程序在使用了std::printf和std::cout的时候不发生混乱,将输出流绑到了一起。
cin,cout之所以效率低,是因为先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间,使效率与scanf与printf相差无几.

应用
在ACM里,经常出现数据集超大造成 cin 运行超时 /Time Limit Exceeded【TLE】的情况。这时候大部分人(包括原来我也是)认为这是cin的效率不及scanf的错,甚至还上升到C语言和C++语言的执行效率层面的无聊争论。其实像上文所说,这只是C++为了兼容而采取的保守措施。我们可以在IO之前将stdio解除绑定,这样做了之后要注意不要同时混用cout/cin和printf/scanf之类。
tie是将两个stream绑定的函数,空参数的话返回当前的输出流指针。
在默认的情况下cin绑定的是cout,每次执行 << 操作符的时候都要调用flush,这样会增加IO负担。可以通过tie(0)(0表示NULL)来解除cin与cout的绑定,进一步加快执行效率。
https://blog.csdn.net/qq_45475271/article/details/107675845

例如,用 system(“color 0A”); 其中color后面的0是背景色代号,A是前景色代号。各颜色代码如下:

0=黑色 1=蓝色 2=绿色 3=湖蓝色 4=红色 5=紫色 6=黄色 7=白色 8=灰色 9=淡蓝色 A=淡绿色 B=淡浅绿色 C=淡红色 D=淡紫色 E=淡黄色 F=亮白色

strstr

char* strstr(const char* haystack, const char* needle);
它的功能是在 haystack 字符串中寻找第一次出现 needle 字符串的位置,并返回该位置的指针。如果没有找到,就返回 NULL。

unique()是C++标准库函数里面的函数,其功能是去除相邻的重复元素(注意一定是相邻元素,且只保留一个),所以使用前需要对数组进行排序

iterator My_Unique (iterator first, iterator last)//两个参数都是迭代器
{
if (first==last)
return last; // 只有一个元素的情况
iterator result = first; // 从第一个元素开始
while (++first != last) // 直到最后一个元素
{
if (*result != *first) // 找到了一个不重复的元素
*(++result)=*first; // 覆盖前面的元素
}
return ++result; // 返回最后不重复元素的下一个元素的坐标的迭代器
}
长度为L的数组a,unique(a,a+n) - a返回的是去重后的数组长度k

erase

(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符

(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)

(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)

原文链接:https://blog.csdn.net/weixin_41969587/article/details/82587372

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
原文链接:https://blog.csdn.net/qq_40160605/article/d100ils/80150252

>>

有符号右移位,将运算数的二进制整体右移指定位数,正数高位用0补齐,负数高位用1补齐(保持负数符号不变)

正数:5>>2

1、转化为二进制:

0000 0000 0000 0000 0000 0000 0000 0101

2、整体右移指2位数

0000 0000 0000 0000 0000 0000 0000 0001

>>>

无符号右移位,不管正数还是负数,高位都用0补齐(忽略符号位)

结构体初始化

结构体可以通过多种方式进行初始化。下面是一些常见的初始化方法:

使用大括号({})进行初始化:

struct Person {
std::string name;
int age;
};

Person p = {“Tom”, 20}; // 使用大括号进行初始化

使用构造函数进行初始化:

struct Person {
std::string name;
int age;
Person(std::string n, int a) : name(n), age(a) {} // 定义构造函数
};

person(string name, int age):name(" "), age(0){}
Person p(“Tom”, 20); // 使用构造函数进行初始化

使用C++11新引入的列表初始化(也称为统一初始化):

struct Person {
std::string name;
int age;
};

Person p{“Tom”, 20}; // 使用列表初始化

map

它提供一对一,每个关键字只能在map中出现一次,

对数据自动排序的功能,所以在map内部所有的数据都是有序的,

自动建立Key - value的对应。key 和 value可以是任意你需要的类型。

根据key值快速查找记录,查找的复杂度基本是Log(N)

快速插入Key -Value 记录。

快速删除记录

根据Key 修改value记录。

遍历所有记录。

    map<int, string> mapStudent;  
    mapStudent.insert(pair<int, string>(1, "student_one")); 
   
    map<int, string>::iterator iter;  
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
    cout<<iter->first<<' '<<iter->second<<endl;  

set清除用clear

set自定义排序
1.struct CustomCompare {
bool operator()(int a, int b) const {
// 自定义比较规则,例如降序排列
return a > b;
}
};
std::set<int, CustomCompare> s;

2.bool customCompare(int a, int b) {
// 自定义比较规则,例如降序排列
return a > b;
}
std::set<int, bool(*)(int, int)> s(customCompare);

快速幂 + - * 先取 %

2^34324
a[0] = 1;
a[1] = 2;
101111

int -2^31 ~ 2^31 - 1

int 类型通常用于表示 32 位整数,其范围是 -2,147,483,648 到 2,147,483,647。具体范围可能因编译器和平台而异,但至少保证在 -32,767 到 32,767 之间。 1e10

long long

long long 类型用于表示 64 位整数,其范围是 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。 1e19

最小公倍数

用 辗转相除法算最大公约数 b|a (b为a的因数, a为b的倍数)
当 b | a , gcd(a, b) = gcd(a, a - b) gcd(a, b) = gcd(b, a % b)
a, b, tmp
whie(!b)
{
tmp = a % b;
a = b;
b = tmp;
}
##nim博弈
有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。

这游戏看上去有点复杂,先从简单情况开始研究吧。
如果轮到你的时候,只剩下一堆石子,那么此时的必胜策略肯定是把这堆石子全部拿完一颗也不给对手剩,然后对手就输了。
如果剩下两堆不相等的石子,必胜策略是通过取多的一堆的石子将两堆石子变得相等,以后如果对手在某一堆里拿若干颗,你就可以在另一堆中拿同样多的颗数,直至胜利。
如果你面对的是两堆相等的石子,那么此时你是没有任何必胜策略的,反而对手可以遵循上面的策略保证必胜。
如果是三堆石子……好像已经很难分析了,看来我们必须要借助一些其它好用的(最好是程式化的)分析方法了,或者说,我们最好能够设计出一种在有必胜策略时就能找到必胜策略的算法。

异或 运算符

##nim博弈
https://zhuanlan.zhihu.com/p/616286372
当先手遇到的异或的值不为0的话,一定可以拿走一些石子使得后手面对的局面异或值为0,且后手不管怎么拿留给先手的异或值必然不为0

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=image-4.png&pos_id=img-xxPKQIxS-1698454585305在这里插入图片描述

Georgia and Bob

https://blog.csdn.net/weixin_43311695/article/details/104570854
将相邻两棋子间的距离当做石子,因为每次一轮移动即可将这两棋子放在入口,则根本不用考虑他在哪个位置 只需要考虑 间距 因为不允许反超 相对位置不变且移动相当于石子减少

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值