数学(二分,交点,快速米,找子串)

组合数+快速幂

int kmp(int a,int k)
{
int ans=1;
while (k)
{
if(k&1) ans=ans*a%mod;
k>>=1;
a=a*a%mod;
}
return ans;
} // 快速幂


///这个是预处理,全部算出来,进行多次询问
int fct[N], inv[N];///inv是分母,fct是1到i的一段乘

void init(int n)
{

fct[0]=1,inv[0]=ksm(1,mod-2);
for (int i=1;i<=n;i++) {
fct[i]=fct[i-1]*i%mod;
inv[i]=ksm(fct[i],mod-2); ///逆元算除法,既可以乘
}
}

int C(int a,int b)
{
if (b>a) return 0;
return fct[a]*inv[b]%mod*inv[a-b]%mod; ///到a的一段除以b在除以a-b这一段多余的
}

 

///下面是当你不多次询问,问一次算一次的写法

int C(int a, int b) ///a是下标,b是上标
{
int res = 1;
for (int i = 1, j = a; i <= b; i ++, j -- )
{
res = (int)res * j % mod;
res = (int)res * ksm(i, mod - 2) % mod;
}
return res;
}


int lucas(int a, int b) {
if (a < mod && b < mod) return C(a, b);
return (int) C(a % mod, b % mod) * lucas(a / mod, b / mod) % mod;

}

 

二分(整数+浮点数)

整数:
int l=0,r=1e9;
int ans;
while (l<=r)
{
int mid=(l+r)>>1;
if(ch(mid)) l=mid+1,ans=mid; ///具体跑区间转换具体题看
else r=mid-1;
}
浮点数:
bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

 二维前缀和

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

 二维差分

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c




正式代码,得出的a就是进行区间加减后的结果
for(int i=1;i+k-1<=n;i++) {
for (int j = 1; j + k - 1 <= m; j++) {
a[i][j] += 1;
a[i + k][j + k] += 1;
a[i + k][j] -= 1;
a[i][j + k] -= 1;
}
}
for(int i=1;i<=n;i++) {
for (int j = 1; j <= m; j++) {
a[i][j] += (a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1]);
}
}
 

离散化

#include <bits/stdc++.h>
//#pragma GCC optimize("Ofast")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
//#define double long double
#define int long long
//#define endl '\n';
using namespace std;
const int N=3e6+7,M=1e1;
const int INF = 0x3f3f3f3f;
const int mod=100003;
typedef pair<int,int> PII;


vector<PII> a;
vector<PII> b;
vector<int> all;
int ans[N];
int s[N];
int n,m;
int find(int  x)
{
    int l,r;
    l=0,r=all.size()-1;
    while (l<r)
    {
        int mid=(l+r)/2;
        if(all[mid]>=x) r=mid;
        else l=mid+1;
    }
    return r+1;
}

void solve()
{

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int c,x;
        cin>>x>>c;
        a.push_back({x,c});

        all.push_back(x);
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        cin>>l>>r;
        b.push_back({l,r});

        all.push_back(l);
        all.push_back(r);
    }
    sort(all.begin(),all.end());
    all.erase(unique(all.begin(),all.end()),all.end());

    for(auto i:a)
    {
        int x= find(i.first);
        ans[x]+=i.second;
    }

    for(int i=1;i<=all.size();i++)
    {
        s[i]=s[i-1]+ans[i];
    }

    for(auto i:b)
    {
        cout<<s[find(i.second)]-s[find(i.first)-1]<<endl;
    }
}
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int T=1;
//    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

 

 

二分图,匈牙利每一个数找对应最优数

vector<int> a[N];    ///根据题目要求
int vis[N];       ///标记这个点符合条件,但是没有匹配成功
int zhan[N];      ///谁占用了当下元素
bool dis(int x)
{
    for(auto i:a[x])
    {
        if(vis[i]) continue;
        vis[i]=1;
        if(!zhan[i] || dis(zhan[i]))        ///判断占用这个点的东西能不能不占用这个点换一个目标
        {
            zhan[i]=x;
            return 1;
        }
    }
    return 0;
}


记得更新vis
  for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof vis);        ///记得初始化,因为每次都需要对要求点扫描一下
        if(!dis(i)) ans++;
    }

 

 最长上升子序列

 vector<int> f(N,INF);
    int ma=-1;
    for(int i=1;i<=n;i++)
    {
        int id= lower_bound(f.begin(),f.end(),a[i])-f.begin();
        f[id]=a[i];
        ma=max(ma,id+1);
    }

 o拉筛(质数)

vector<int> prime;
bool st[N];
void pr(int n)
{
    st[1]= true;
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime.push_back(i);
        for(int j:prime)
        {
            if(j*i>n) break;
            st[j*i] = true;
            if(i%j==0) break;
        }
    }
}

 

 

线段和线段直接求交点

1.求两直线的交点(两点式)

    Point p1,p2,p3,p4;//对应的四个点,根据实际应用场景赋值
    double a1, a2, a3, b1, b2, b3;
    double t;
    Point pp1, pp2;
    a1 = p4.y - p3.y;
    a2 = p3.y - p1.y;
    a3 = p2.y - p1.y;
    b1 = p4.x - p3.x;
    b2 = p3.x - p1.x;
    b3 = p2.x - p1.x;
    t = (a3 * b2 - a2 * b3) / (a1 * b3 - a3 * b1);
    pp1.x = (p4.x - p3.x) * t + p3.x;
    pp1.y = (p4.y - p3.y) * t + p3.y;

2.求两直线的交点(斜截式)

    Point p1,p2;//对应的两个点,根据实际应用场景赋值
    vector<Point> points;//用来拟合直线的点
    Vec4f line;
    fitLine(points, line, DIST_L2, 0, 0.01, 0.01);//拟合得到直线,具体求解根据实际情况
    double cos_theta = line[0];
    double sin_theta = line[1];
    double x0 = line[2], y0 = line[3];
    double k = sin_theta / cos_theta;
    double b = y0 - k * x0;
    t = (k * p1.x + b - p1.y) / (p2.y - p1.y - k * (p2.x - p1.x));
    Point pp1;
    pp1.x = (p2.x - p1.x) * t + p1.x;
    pp1.y = (p2.y - p1.y) * t + p1.y;

3.求垂足(两点式)

    Point p1,p2;//对应的两个点,根据实际应用场景赋值    
    int a = p2.x - p1.x;
    int b = p2.y - p1.y;
    double t = (a * (p1.y - p3.y) + b * (p3.x - p1.x));
    t = t / (a * a + b * b);//分两步计算,直接一步实现会由于精度问题导致结果出错
    Point p;
    p.x = -b * t + p3.x;
    p.y = a * t + p3.y;

4.求垂足(斜截式)

    Point p3;//直线外一点
    vector<Point> points;//用来拟合直线的点
    Vec4f pline;
    fitLine(points, pline, DIST_L2, 0, 0.01, 0.01);
    cos_theta = pline[0];
    sin_theta = pline[1];
    x0 = pline[2], y0 = pline[3];
    double k1 = sin_theta / cos_theta;
    double b1 = y0 - k1 * x0;
    double b2 = 0;
    double k2 = -1 / k1;
    b2 = p3.y - k2 * p3.x ;
    pp1.x = (b2 - b1) / (k1 - k2);
    pp1.y = k2 * pp1.x + b2;
posted @ 2024-01-28 00:25  whatdo+  阅读(28)  评论(0)    收藏  举报