首页 > 其他分享 >2022 HDU多校9

2022 HDU多校9

时间:2022-09-02 00:56:02浏览次数:62  
标签:HDU le gcd int 多校 cin -- 2022 ans

Arithmetic Subsequence(二进制、思维、分治)

Problem

给定一个长度为\(n\)的序列,问是否可以对它重新排序使得重排后的序列中不存在等差子序列

Solve

  • 如果一个数出现了\(3\)次及以上,一定无解
  • 若\(a_i,a_j,a_k\)成等差数列,那么\(a_i\)和\(a_k\)奇偶性相同,所以如果把偶数放到左边,奇数放到右边,那么不会有横跨两边的等差数列。所以只需递归地去考虑一边
  • 递归时,把偶数除以\(2\),把奇数减\(1\)再除以\(2\)递归即可
  • 一种优化二进制写法:考虑从0 1开始,左边是整体乘\(2\),右边是整体乘\(2\)加\(1\),得到0 2 1 3,继续0 4 2 6 1 5 3 7。写成而二进制的形式000 100 010 110 001 101 011 111,把这个二进制翻转,得到000 001 010 011 100 101 110 111,即0 1 2 3 4 5 6 7,所以我们可以把每个数字二进制序列翻转后排序即可构造一个合法的序列
    \(1\le n\le 5000\)

Solve

Code

#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        map<int,int>cnt;
        vector<pair<int,int>>a(n);
        auto rev=[&](int x)->int{
           int ans=0;
           for(int i=30;i>=0;i--,x>>=1){
            ans|=(x&1)<<i;
           }
           return ans;
        };
        for(int i=0;i<n;i++){
            cin>>a[i].second;
            cnt[a[i].second]++;
            a[i].first=rev(a[i].second);
        }
        bool ok=1;
        for(auto t:cnt){
           if(t.second>=3){
              ok=0;
              break;
           }
        }
        if(!ok) cout<<"NO\n";
        else{
           cout<<"YES\n";
           sort(a.begin(), a.end());
           for(auto x:a) cout<<x.second<<" ";
            cout<<'\n';
        }
    }
}

Fast Bubble Sort(单调栈、倍增)

Problem

给定长度为\(n\)的排列\(\{p_i\}\),\(q\)次询问,每次给出一个区间\([l,r]\),问要对该区间进行多少次子区间的循环平移(\(a_i a_{i+1}\cdots a_j\rightarrow a_{i+1}\cdots a_{j} a_{i}\)或者\(a_ia_{i+1}\cdots a_j \rightarrow a_{j}a_{i}\cdots a_{j-1}\)),变成\(B(p[l,r])\),其中\(B(p[l,r])\)的操作是

int* B(int *p, int x, int y)
{
    for(int i=x;i<y;i++)
        if(p[i]>p[i+1])
            swap(p[i],p[i+1]);
    return p;
}

\(1\le n,q\le 10^5\)

Solve

首先判断\(B\)的作用是什么:假设当前位置是\(i\),假设右边第一个比\(a_i\)大的数的位置是\(j\),那么把\(a_i\)移动到\(j-1\)和\(j\)之间的位置,然后从\(j\)开始继续这样的交换操作。

找右边第一个比\(a_i\)大的数,很容易想到使用单调栈来操作,记作\(r_i\),如果\(r_i=i+1\),那么就不需要操作。问题变成了现在询问给定一个区间\([l,r]\),\([l,r_l-1],[r_l,r_{r_l}-1]\cdots [r_j+1,r]\)有多少段,并且两端断点之间的差值大于\(2\)。考虑\(f_{i,j}\)表示在位置\(i\)经过\(2^j\)次跳跃可以到达的位置,并且我们倒序转移,维护一个\(val\)表示从\(i\)到\(n\)有多少个可以跳跃的\(r_j\),然后对于给定的询问\([l,r]\),倍增找出最后一个小于\(r\)的\(r_j\)的位置\(j\),然后利用一次后缀和作差\(val[l]-val[j]\)即可求出需要跳跃的次数。

Code

#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin>>T;
    while(T--){
        int n,q;
        cin>>n>>q;
        vector<int>stk(n+1),p(n+1),r(n+1);
        for(int i=1;i<=n;i++) cin>>p[i];
        int top=0;
        for(int i=n;i>=1;i--){
           while(top && p[i]>p[stk[top]]) top--;
           if(!top) r[i]=n+1;
           else r[i]=stk[top];
           stk[++top]=i;
        }
        vector<vector<int>>f(n+3,vector<int>(25,n+1));
        vector<int>val(n+2);
        for(int i=n;i>=1;i--){
            val[i]=val[r[i]]+(r[i]>i+1);
            f[i][0]=r[i];
            for(int j=1;j<=20;j++) f[i][j]=f[f[i][j-1]][j-1];
        }
        while(q--){
            int l,r;
            cin>>l>>r;
            int i=l;
            for(int j=20;j>=0;j--){
                if(f[i][j]<=r){
                    i=f[i][j];
                }
            }
            int ans=val[l]-val[i];
            if(r!=i) ans++;
            cout<<ans<<'\n';
        }
    }
}

Matryoshka Doll(DP)

Problem

给定\(n\)个套娃的大小为\(\{a_i\}\),一个大小为\(x\)的套娃能放入大小为\(y\)套娃中当且仅当\(x+r\le y\)。问把这\(n\)个套娃分成\(k\)组,每组中小的一定可以放入大的中的方案数。\(1\le n,k\le 5000\)

Solve

由于\(\{a\}\)是单调不减的,所以我们可以\(O(n^2)\)预处理出每个数不能和前面的哪些数放在一起,记作\(ban_i\),并且不能与\(i\)在一起的数也不能在同一组里面,因为假设有两个\(a_{j_1}+r \gt a_i\),\(a_{j_2}+r\gt a_i\),并且\(j_1\lt j_2\),因为\(\{a\}\)是单调不减的,所以若\(a_{j_1}\)和\(a_{j_2}\)可以在一个组里,那么\(a_{j_1}+r\le a_{j_2}\le a_i\),矛盾。

定义\(dp_{i,j}\)表示前\(i\)个数分成\(j\)组的方案数。转移分两种中情况,类似于斯特林数的递推:

  • 第\(i\)个数自己一个一组,那么\(dp_{i,j}+=dp_{i-1,j-1}\)
  • 第\(i\)个数放到前面可以与它在一组的组里面,那么\(dp_{i,j}+=dp_{i-1,j}\times (j-ban_i)\)

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin>>T;
    while(T--){
        int n,k,r;
        cin>>n>>k>>r;
        vector<int>ban(n+1),a(n+1);
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++)
                if(a[i]<r+a[j]) ban[i]++;
        }
        vector<vector<ll>>dp(n+1,vector<ll>(k+1));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=min(i,k);j++){
                dp[i][j]=(dp[i-1][j-1]+dp[i-1][j]*(j-ban[i])%mod)%mod;
            }
        }
        cout<<dp[n][k]<<'\n';
    }
}

Shortest Path in GCD Graph(数论、莫比乌斯反演)

Problem

有\(n\)个点,每两个点\((i,j)\)之间的路径边权是\(\gcd(i,j)\),有\(q\)次询问,每次给定两个点,问这两个点之间的最短路径是多少,并求出有多少条。

\(1\le n\le 10^7\),\(1\le q\le 5\times 10^4\)

Solve

  • 若\(\text{gcd}(u,v)=1\),那么最小路径就是\(1\),并且只有\(u,v\)直接连接的这一条路径
  • 若\(\text{gcd}(u,v)\ne 1\),那么最小路径就是\(2\),我们选一个和\(u,v\)都互质的点作为中转点即可。而这个路径条数就是\(1\)到\(n\)中即和\(u\)也和\(v\)互素的数的个数,所以问题变成了就\(\sum_{i=1}^n [gcd(i,u)==1][gcd(i,v)==1]\)的答案。

\[\sum_{i=1}^n [gcd(i,u)==1][gcd(i,v)==1]\\ =\sum_{i=1}^n [gcd[i,lcm(u,v)]==1]\\ =\sum_{d|lcm(u,v)}\mu(d) \lfloor \frac{n}{d} \rfloor \]

注意到\(\mu(d)\)的只有不存在偶数次幂的素因子的时候才不为\(0\),所以类似于\(PN\)筛的思想,我们只取有值的地方计算即可,并且不直接计算\(lcm(u,v)\)的素因子,而是把分别求\(u,v\)的素因子后去重得到\(lcm(u,v)\)的素因子,然后类似于\(PN\)筛DFS即可。

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353;
const int N=1e7;
int prime[N+5],st[N+5],cnt,mu[N];
void get_primes(int n){
    mu[1]=1;
     for(int i=2;i<=n;i++){
        if(!st[i]) prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt && prime[j]*i<=n ;j++){
            st[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
     }
}

set<int>factor;
vector<int>p;
void divide(int x){
    for(int i=2;i*i<=x;i++){
        if(x%i==0){
            factor.insert(i);
            while(x%i==0){
                x/=i;
            }
        }
    }
    if(x>1) factor.insert(x);
}
ll ans;
int n,q;
void dfs(int i,ll d){
    if(d>n){
        return;
    }
    if(i==int(p.size())){
        ans+=mu[d]*(n/d);
        return;
    }
    dfs(i+1,d*p[i]);
    dfs(i+1,d);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>q;
    get_primes(n);
    while(q--){
        int u,v;
        cin>>u>>v;
        int k=__gcd(u,v);
        if(k==1){
            cout<<1<<" "<<1<<'\n';
        }
        else{
            cout<<2<<" ";
            factor.clear();
            p.clear();
            divide(u),divide(v);
            ans=0;
            for(auto x:factor) p.push_back(x); 
            dfs(0,1);
            cout<<ans+(k==2)<<'\n';

        }
    }
}

Sum Plus Product(数学推导)

Problem

给定长度为\(n\)的序列\(\{a\}\),每次等概率地从序列从选出两个数\(a,b\),然后放回\(ab+a+b\),问最后剩下的一个数期望是多少

Solve

  • hit1:\(ab+a+b=(a+1)(b+1)-1\)
    可以发现最后的答案是固定的,即\(\prod_{i=1}^n(a_i+1)-1\)

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        ll ans=1;
        for(int i=1;i<=n;i++){
            int x;
            cin>>x;
            ans=ans*(x+1)%mod;
        }
        ans=(ans-1+mod)%mod;
        cout<<ans<<'\n';
    }
}

The Alchemist of the Discrete Mathematics(多项式、数学)

标签:HDU,le,gcd,int,多校,cin,--,2022,ans
From: https://www.cnblogs.com/Arashimu0x7f/p/16648344.html

相关文章

  • 工作感受月记202209月
    2022年09月01日成都静默三天以应对疫情。从杭州桐庐回来后,就开始居家三天,刚准备去公司,遇上了全市静默三天。此刻,在家,写日杂。今日工作事项:1/在做lili和qingbo关于azu......
  • 2022 HDU多校8
    Theramore(思维)Problem给定一个01串,可以进行无限次操作,每次操作可以把一个长度为奇数的区间翻转,问可以得到的字典序最小的01串是多少Solvehit1:反转后奇数位置还是在......
  • The 2022 Hangzhou Normal U Summer Trials
    A.Hello,ACMer!这题就是找到hznu的个数#include<bits/stdc++.h>usingnamespacestd;int32_tmain(){strings;cin>>s;intcnt=0;for(i......
  • 数据库学习笔记 (本数据库学习笔记以SQL sever 2019 为例进行学习) 20220831 第四节课
    两层映像两层映像E-CMapping:ExternalSchema-ConceptualSchemaMapping----将外模式映射为概念模式,从而支持实现数据概念视图向外部视图的转换----便于用户观察和......
  • 2022 8 29
    https://www.lanqiao.cn/problems/1463/learning/主要是运行时间问题:importosimportsysn=2021041820210418l=[]i=2x=nwhilei<pow(x+1,0.5):ifx%i==0......
  • 2022-09-01 第二小组 张晟源(ajax,axios)
    JavaWeb一,AJAX异步刷新(局部刷新),前端技术,可以给后台发请求异步:整个页面不会全部刷新,只有某个局部刷新  验证用户名存在 使用ajax发送请求,页面不可以通过后台跳转......
  • NOI2022(部分)题解
    D1T1:严格众数有一种处理方法就是摩尔投票法:既然这个众数\(x\)出现了超过\(\dfracn2\)次,那么我们每次把一个非众数\(y\)和\(x\)消掉,即使是在最劣情况下,最后一定......
  • 2022-8-31 jsp el表达式
    jsp<%--JSP脚本片段:用于在JSP页面写java代码--%>注意:1、JSP脚本片段中只能出现java代码,不能出现HTML元素。在 访问JSP时,JSP引擎翻译JSP页面中的......
  • 2022-9-1 第一组 (≥▽≤) 学习笔记
    目录1.AjaxJS原生的AjaxGET请求POST请求JQuery的Ajax发送GET请求发送POST请求完整写法Vue的Ajax(aixos)GET请求POST请求注意点:1.Ajax异步刷新(局部刷新),前端技术——可以给......
  • 2022-09-01 第四组 王佳齐 学习笔记
    ajax概念ajax:异步刷新,前端技术,给后台发请求异步:整个页面不会全部刷新只有某个局部在刷新。四种发请求的方式:1.form表单2.a标签3.地址栏4.location.href.window.ope......