2023.8.2

2022河南萌新联赛第(三)场:河南大学\神奇数字.cpp

//题意:给定三个正整数a b c,求x满足满足abc同余x的个数。

//这个考虑同余的性质,就是两个数的差去取模为0的数肯定是这两个数的同余数,。因此我们计算三个数两两之间差的最大公约数,然后直接分解质因数,计算gcd的因子个数就是x能够用取到的数量。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;



#define endl '\n'

typedef pair pr;



#define int long long

#define ll long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define ufr(i,n,z) for(int i = n;i >= z; i--)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int n,m;



int a[N];

int gcd(int a,int b){

    return !b?a:gcd(b,a%b);

}

void solve()

{

    int a,b,c;

    cin>>a>>b>>c;

    if(a==b&&a==c){

        cout<<-1<<'\n';

        return ;

    }

    int x=gcd(abs(a-b),abs(b-c));

    vectorv;

    for(int i=1;i*i<=x;i++){

        if(x%i==0){

            if(i!=x/i)v.push_back(x/i);

            v.push_back(i);

        }

    }

    sort(v.begin(),v.end());

    fr(i,0,v.size()-1){

        cout<>t;

    while(t--) solve();

    return 0;

}

总结://同余的性质 (就是两个数的差去取模为0的数肯定是这两个数的同余数)
//同余式可逐项相加
//同余式可以逐项相乘。
//同余式一边的数可以移到另一边,只要改变符号就可以了
//同余式的每一边都可以增加或减去模的任意倍数。
//同余式两边的数如有公约数,此公约数又和模互素,那么就可以把两边的数除以这个公约数。
//同余式两边的数和模可以同时乘上一个整数。
//同余式两边的数和模可以同时被它们任一公约数除。
//如果同余式对于模m成立,那么它对于m的任意约数相等的模d也成立。
//如果同余式一边上的数和模能被某个数除尽,则同余式的另一边的数也能被这个数除尽。
//同余式一边上的数与模的最大公约数,等于另一边上的数与模的最大公约数

2022河南萌新联赛第(三)场:河南大学\逆序对计数.cpp

//题意:给定长度为n的排列(0<=n<=6000),每次询问为如果将l,r翻转,则逆序对的个数

//思路: 对于一个排列, 如果区间反转, 逆序数等于区间中所有的对数减去当前的逆序对数, 即原本的正序对变为逆序对, 原本的逆序对变为正序对。

//改变区间在整个区间的位置不重要,逆序对的增减只会在区间进行

/* #include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;



#define endl '\n'

typedef pair pr;



#define int long long

#define ll long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define ufr(i,n,z) for(int i = n;i >= z; i--)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int n,m;



int a[N];

int s[6010][6010];

int change(int l,int r){

    int len=r-l+1;

    int x=len*(len-1)/2;

    return x-2*s[l][r];

}

void solve()

{

    cin>>n;

    fr(i,1,n){

        cin>>a[i];

    }

    int res=0;

    fr(i,1,n){           //预处理所有l,r的逆序数个数

       fr(j,1,i){

         s[j][i]=s[j][i-1];

       }

        int cnt=0;

        ufr(j,i-1,1){

            if(a[j]>a[i]){

               cnt++;

               res++;

            }

            s[j][i]+=cnt;

        }

    }

    cin>>m;

    while(m--){

        int l,r;

        cin>>l>>r;

        cout<>t;

    while(t--) solve();

    return 0;

} */

//树状数组做法

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;



#define endl '\n'

typedef pair pr;



#define int long long

#define ll long long

#define fr(i,l,r) for(int i=l;i<=r;i++)

#define ufr(i,n,z) for(int i = n;i >= z; i--)

#define pb(x) push_back(x)

#define all(a) a.begin(),a.end()

#define fi first

#define se second



const int N = 1e6+10;

const int mod=998244353,inf=LONG_LONG_MAX;

int n,m;



int a[N];

int t[N];

int f[6010][6010];

void add(int x){

    for(int i=x;i<=n;i+=i&-i){

        t[i]+=1;

    }

}

int query(int x){

    int ans=0;

    for(int i=x;i;i-=i&-i){

        ans+=t[i];

    }

    return ans;

}

void solve()

{

   

    cin>>n;

    fr(i,1,n){

        cin>>a[i];

    }

    fr(i,1,n){

       fr(j,i,n){

          f[i][j]=f[i][j-1]+(j-i-query(a[j]));         //(j-i-query(a[j])即区间-正序对个数

          add(a[j]);

       }

       fr(j,1,n){

         t[j]=0;

       }

    }

    cin>>m;

    int res=f[1][n];

    while(m--){

        int l,r;

        cin>>l>>r;

        cout<>t;

    while(t--) solve();

    return 0;

}

P1045 [NOIP2003 普及组] 麦森数(高精度快速幂)
题意:输入P(1000<=p<=3100000),输出2^p-1的位数及最后500位数
 

#include
#include
#include
using namespace std;
int f[1001], p, res[1001], sav[1001];//乘法要开两倍长度
void result_1() {
    memset(sav, 0, sizeof(sav));
    for (register int i = 1; i <= 500; i += 1)
        for (register int j = 1; j <= 500; j += 1)
            sav[i + j - 1] += res[i] * f[j];//先计算每一位上的值(不进位)
    for (register int i = 1; i <= 500; i += 1)
    {
        sav[i + 1] += sav[i] / 10;//单独处理进位问题,不容易出错
        sav[i] %= 10;
    }
    memcpy(res, sav, sizeof(res));//cstring库里的赋值函数,把sav的值赋给res
}
void result_2() {
    memset(sav, 0, sizeof(sav));
    for (register int i = 1; i <= 500; i += 1)
        for (register int j = 1; j <= 500; j += 1)
            sav[i + j - 1] += f[i] * f[j];
    for (register int i = 1; i <= 500; i += 1){
        sav[i + 1] += sav[i] / 10;
        sav[i] %= 10;
    }
    memcpy(f, sav, sizeof(f));
}
int main() {
    cin >> p;
    cout << int(log10(2) * p + 1) << '\n';               //2^p-1,2^p的位数
    res[1] = 1;
    f[1] = 2;
    while (p) {
        if (p % 2 == 1) {
            result_1();
        }
        result_2();
        p >>= 1;
    }
    res[1] -= 1;
    for ( int i = 500; i >= 1; i--)//注意输出格式,50个换一行,第一个不用
        if (i != 500 && i % 50 == 0)printf("\n%d", res[i]);
        else printf("%d", res[i]);
    return 0;
}

数位dp

(最高位限制,记忆化搜索,枚举位的大小,前导0)

洛谷P2657 [SCOI2009] windy 数

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。
 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?

#include
#include
using namespace std;
int num[12], dp[12][12];
int dfs(int pos, int pre, int limit, int lead) {
    int ans = 0, i, up;
    if (pos == -1)  //搜完
        return 1;      //用作计数
    if (!limit && dp[pos][pre] != -1 && !lead)//没有最高位限制,已经搜过了,并且没有前导0
        return dp[pos][pre];      //记忆化搜索
    up = limit ? num[pos] : 9;//当前位最大数字 
    for (i = 0; i <= up; i++) {//从0枚举到最大数字 
        if (lead) {//有前导0不受限制 
            ans += dfs(pos - 1, i, limit && i == up, lead && i == 0);
        }
        else if (i - pre >= 2 || i - pre <= -2)//无前导0受限 
            ans += dfs(pos - 1, i, limit && i == up, lead && i == 0);
    }
    if (!limit && !lead)//没有最高位限制且没有前导0时记录结果 
        dp[pos][pre] = ans;
    return ans;
}
int solve(int x) {
    int pos = 0;
    while (x) {
        num[pos++] = x % 10;
        x /= 10;
    }   //按位储存
    return dfs(pos - 1, -1, 1, 1);
}
int main() {
    ios::sync_with_stdio(false);
    int lt, rt;
    cin >> lt >> rt;
    memset(dp, -1, sizeof(dp));
    cout<< solve(rt) - solve(lt - 1)<<'\n';
    return 0;
}

你可能感兴趣的:(算法,c++,数据结构)