1 高精度
注意 printf(""%Lf",a);不需要取地址
1)R问题
https://www.lanqiao.cn/problems/19710/learning/
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
string d; //数太大用字符数组读
cin >> n >> d;
vector<int>b; //开vetor好处就是可以用push_back进位的时候可以在后面直接加
int sum = 0, k = 0;
for (int i = d.size() - 1;i >= 0;i--)
{
if (d[i] != '.')
b.push_back(d[i] - '0'); //把字符型变成整数型
else { k = sum; }//sum 用于记录当前处理的是第几位数字
sum++; //找到小数点位置为以后输出做铺垫,现在就可以看作一个大整数了
}
int u = b.size();
//这里相当于模拟了高精度大数乘小数
while (n--) //指数类型太大,保存不了,故每次*2
{
int t = 0;
for (int i = 0;i < b.size();i++)
{
b[i] = b[i] * 2 + t; //t是进位的数
if (b[i] >= 10)
{
t = b[i] / 10;
b[i] = b[i] % 10;
}
else t = 0;
}
if (t)
b.push_back(t);
} //模拟数学过程
u = b.size();
int t = 1;
if (k && b[k - 1] >= 5) { // 四舍五入过程,如果存在小数点(k 不为 0),并且小数点后第一位(b[k - 1])大于等于 5
for (int i = k;i < u;i++)
{
b[i] = b[i] + 1;
if (b[i] <= 9) { t = 0;break; }
else b[i] -= 10;
}
if (t) b.push_back(t);
//注意余数处理
}
for (int i = b.size() - 1;i >= k;i--)
cout << b[i];
return 0;
}
2深搜
1)路径数字接龙
https://www.lanqiao.cn/problems/19712/learning/
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 11; // 定义棋盘的最大大小为11×11
int n, k; // n为棋盘大小,k为数字循环的范围
int g[N][N]; // 存储棋盘上的数字
int dx[8] = { -1, -1, 0, 1, 1, 1, 0, -1 }; // 定义8个方向的x坐标偏移
int dy[8] = { 0, 1, 1, 1, 0, -1, -1, -1 }; // 定义8个方向的y坐标偏移
string path; // 存储路径的方向编号
bool st[N][N]; // 标记棋盘上的格子是否被访问过
bool edge[N][N][N][N]; // 检查路径是否交叉
// 深度优先搜索函数,用于寻找路径
bool dfs(int a, int b) {
// 如果到达右下角格子,检查路径长度是否为n*n-1(因为起点不计入路径)
if (a == n - 1 && b == n - 1)
return path.size() == n * n - 1;
st[a][b] = true; // 标记当前格子已访问
for (int i = 0; i < 8; i++) { // 遍历8个方向
int x = a + dx[i], y = b + dy[i]; // 计算目标格子的坐标
// 检查目标格子是否越界、是否访问过、数字是否满足循环序列要求
if (x < 0 || x >= n || y < 0 || y >= n) continue;
if (st[x][y]) continue;
if (g[x][y] != (g[a][b] + 1) % k) continue;
// 检查路径是否交叉(对于斜向移动,检查是否有反向的路径)
if (i % 2 && (edge[a][y][x][b] || edge[x][b][a][y])) continue;
edge[a][b][x][y] = true; // 标记路径
path += i + '0'; // 将方向编号加入路径
if (dfs(x, y)) return true; // 递归搜索下一个格子
/*
即使深层递归返回 true,当前层如果没有及时返回,
就会继续执行其他方向的尝试,而回溯会覆盖已经找到的路径。
例如,当某个方向找到了正确路径,当前层的 dfs 函数应该立即返回 true,
让上层知道已经找到解,从而终止搜索。
如果没有 if 语句,当前层会继续处理其他方向,可能导致路径被覆盖或重复计算。*/
path.pop_back(); // 回溯,移除路径中的最后一个方向
edge[a][b][x][y] = false; // 回溯,取消路径标记
}
st[a][b] = false; // 回溯,取消当前格子的访问标记
return false; // 如果所有方向都无法到达终点,返回false
}
int main() {
cin >> n >> k; // 输入棋盘大小和数字循环范围
for (int i = 0; i < n; i++) // 读取棋盘上的数字
for (int j = 0; j < n; j++)
cin >> g[i][j];
// 从起点(0,0)开始搜索路径
if (!dfs(0, 0))
cout << -1 << endl; // 如果没有找到路径,输出-1
else
cout << path << endl; // 输出路径的方向编号序列
return 0;
}
3 双指针
1)拔河
解法一:前缀和暴力得出所有解,然后遍历每种相邻的解,选出差值最小的,如果重叠就相当于没选重叠部分。
点击查看代码
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=1e3+10;
int n,js=1,a[N],check[N*N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){//我们先通过二层循环,暴力出每一种选法
int s=0;
for(int j=i;j<=n;j++){
s+=a[j];
check[js++]=s;
}
}//可能有谁都不选的选法,check数组从0开始
sort(check,check+js);
//将他们从小到大排序,力量值之和差距最小的一定是相邻的两种选法
//不用管区间选择重叠的情况,重叠部分相当于两种选法都没选重叠部分
int ans=1e12+10;
for(int i=1;i<js;i++)ans=min(ans,check[i]-check[i-1]);
cout<<ans;
return 0;
}
解法二:双指针,通过++实际实现了四个指针。我当时想直接用双指针,但是头尾指针,感觉会限制在头尾选,或者要有两个区间感觉需要四个指针这里就是四个指针,lr指定了从哪开始,然后通过++指定了延申到哪。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 4;
int n;
vector<ll>a(N);
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
ll ans = 1e14;
for (int l = 1;l <= n;l++)
{
for (int r = n;r > l;r--)
{
//双指针 i 和 j 分别指向区间的左右端点
/*
我当时想直接用双指针,但是头尾指针,感觉会限制在头尾选,或者要有两个区间感觉需要四个指针
这里就是四个指针,lr指定了从哪开始,然后通过++指定了延申到哪/
*/
int i = l, j = r;
ll sum1 = a[i], sum2 = a[j];
ans = min(ans, abs(sum1 - sum2));
if (ans == 0)
{
cout << 0;
return 0;
}
while (i + 1 <= j)
{
if (sum1 == sum2)
{
cout << 0;
return 0;
}
if (sum1 > sum2)
{
j--;
sum2 += a[j];
}
else if (sum1 < sum2)
{
i++;
sum1 += a[i];
}
ans = min(ans, abs(sum1 - sum2));
}
}
}
cout << ans;
return 0;
}
理解错误,给出的数不一定要全部选
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
const int maxn = 1e3 + 10;
int a[maxn];
int sum[maxn];
int ans1, ans2;
int ans = 1e9 + 1;
signed main()
{
cin >> n;
for (int i = 1;i <= n;i++)
cin >> a[i];
for (int i = 1;i <= n;i++)
{
sum[i] += sum[i - 1] + a[i];
}
for (int i = 1;i <= n;i++)
{
ans1 = sum[i];
ans2 = sum[n] - sum[i];
ans = min(abs(ans1 - ans2), ans);
}
cout << ans;
}
2)子序列问题
https://www.lanqiao.cn/problems/3492/learning/
很典型但是没想到咋做,双指针,匹配主串++,不匹配子串++。仍旧是吧答案列出来,然后倒退每个答案是否符合
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
int mon[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12 };
int day[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
string str = "5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3";
int ans = 0;
bool check(string ss) {
int i = 0; // 主字符串的指针
int j = 0; // 待匹配字符串的指针
while (i < str.length() && j < ss.length()) {
if (str[i] == ss[j]) {
j++; // 若字符相同,移动待匹配字符串的指针
}
i++; // 始终移动主字符串的指针
}
return j == ss.length(); // 若待匹配字符串的指针遍历完,说明包含
}
signed main() {
for (int i = 1;i <= 12;i++)
{
for (int j = 1;j <= day[i];j++)
{
string mo = to_string(mon[i]);
string da = to_string(j);
if (i < 10)
mo = "0" + mo;
if (j < 10)
da = "0" + da;
s = "";
s += "2023" + mo + da;
//这里没重置s产生累加问题
if (check(s) == 1)
ans++;
}
}
cout << ans << endl;
}
3 暴力枚举
1)01串计算
https://www.lanqiao.cn/problems/3498/learning/
需要注意fabs是取浮点数的绝对值,然后就是log2可以直接调用数学函数。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main() {
double n = 23333333, sum = 0;
double ans = 11625907.5798;
double minn = 100.0;
int st;
for (int i = 0;i < n / 2;i++)
{
double re = -i * (i / n) * log2(i / n) - (n - i) * ((n - i) / n) * log2((n - i) / n);
if (fabs(re - ans) < minn)
{ minn = fabs(re - ans);
st = i;
}
}
cout << st<< endl;
return 0;
}
浙公网安备 33010602011771号