2020.07.24 福州大學ACM/ICPC集訓隊選拔賽 部分題解


  1. 對於任何一個三角形 \(ABC\) ,令 \(f(A,B,C)\) 表示其三條邊的三個中點構成的點集。
    現在給定 \(f(A,B,C)\) 且滿足所有坐標均為整數,試構造三角形 \(ABC\) 三個頂點坐標。
    保證答案存在且唯一。

中位線定理可得,設三角形 \(DEF\) 對邊的中點分別位 \(ABC\) ,則 \(\vec{BC}={1\over 2}\vec{FE}=\vec{FA}=\vec{AE}\)

因此,考慮求解 \(E\) 點坐標等價於求解 \(\vec{OE}\) 。則 \(\vec{OE}=\vec{OA}+\vec{AE}=\vec{OA}+\vec{OC}-\vec{OB}\)

不難知道,三角形兩中點和減去第三個中點即可得到第三個中點對角的坐標。按這個方法寫完排個序即可。

【代碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
pii operator + (const pii &a,const pii &b) { return pii(a.first+b.first,a.second+b.second); }
pii operator - (const pii &a,const pii &b) { return pii(a.first-b.first,a.second-b.second); }
int main(){
    pii Pnt[5];
    for(int i=1;i<=3;i++) cin>>Pnt[i].first>>Pnt[i].second;
    pii Ans[5];
    Ans[1]=Pnt[1]+Pnt[2]-Pnt[3];
    Ans[2]=Pnt[1]+Pnt[3]-Pnt[2];
    Ans[3]=Pnt[2]+Pnt[3]-Pnt[1];
    sort(Ans+1,Ans+4);
    for(int i=1;i<=3;i++)
        cout<<Ans[i].first<<" "<<Ans[i].second<<endl;
    return 0;
}

  1. 給你兩個長度為 \(len\leq 10^6\)​​ 的由 01 組成的二進制字符串 \(n\)\(m\) 定義 JC 的可愛值為:從 \(1\)\(n\) 中選一個數 \(x\),從 \(1\)\(m\) 中選一個數 \(y\),使得 \((x,y)\) 奇偶性不同的對數.
    下面三個操作一直進行:
    累加 JC 的可愛值.
    字符串 \(n\) , \(m\) 失去他們最后一位,即 \(n=\lfloor{n\over 2}\rfloor,m=\lfloor{m\over 2}\rfloor\) ( \(\lfloor\rfloor\) 表示向下取整).
    如果 \(n=0\),或 \(m=0\) 退出.

不難想出,要使得選出的 \((x,y)\) 奇偶性不同,則必然是 \(x\)\(y\) 一個為奇數,一個為偶數

由於 \(n\) 中的奇數個數為 \(\lfloor{n+1\over 2}\rfloor\) ,偶數個數為 \(\lfloor{n\over 2}\rfloor\)

通過暴力找規律(寫一個代碼,算不同的 \(n,m\) 時,\((\lfloor{n+1\over 2}\rfloor\cdot \lfloor{m\over 2}\rfloor+\lfloor{n\over 2}\rfloor\cdot \lfloor{m+1\over 2}\rfloor)\) )亦或者稍微證明一下,不難發現,每個 \(n,m\) 對答案的貢獻為 \(\lfloor{nm\over 2}\rfloor={nm-(n\&1)\cdot(m\&1)\over 2}\)

現只需考慮如何實現即可:由於 \(nm\) 的乘積在取模意義下等於兩者各自的取模,再乘積的取模。\((n\&1)\cdot (m\&1)\) 僅與最后一位有關

故將串 \(n,m\) 前補足 \(0\) ,使得兩者長度相同。然后從前往后,一邊記錄到當前位置 \(n,m\) 在取模意義下的值,一邊計算對答案的貢獻:若當前二進制位 \(n,m\) 均為 \(1\) ,則對答案的貢獻為 \((nm-1)\mod p\) ,否則為 \(nm\mod p\) 。求和即可算出答案。

【代碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7,inv2=MOD+1>>1,MAXN=1e6+10;;
stack<int> num[3];
string s;
inline ll ans(){
    for(int i=1;i<=2;i++){
        getline(cin,s);
        for(int j=s.size()-1;j>=0;j--)
            num[i].push(s[j]=='1');
    }
    while(num[1].size()<num[2].size()) num[1].push(0);
    while(num[1].size()>num[2].size()) num[2].push(0);
    ll A=0,B=0,Ans=0;
    for(int i=num[1].size();i>0;i--){
        int a=num[1].top(); num[1].pop();
        int b=num[2].top(); num[2].pop();
        A=((A<<1)|a)%MOD;
        B=((B<<1)|b)%MOD;
        ll Tmp=A*B-(a&b);
        Tmp=Tmp%MOD*inv2%MOD;
        Ans=(Ans+Tmp)%MOD;
    }
    return Ans;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout<<ans()<<endl;
    return 0;
}

  1. 胖達發現有 \(n\) 只熊貓在甜筒攤前排了一個隊伍,從前往后依次編號為 \(1,2,\cdots n\)
    胖達還發現,熊貓們不喜歡老實排隊。每過一會兒,會有編號為 \(i\) 的熊貓從隊伍里走出來並插到隊伍的最前面去,或者從隊伍里走出來並排到隊伍的末尾
    胖達很無聊,所以他時不時會問當前隊伍從前往后第 \(i\) 個位置的熊貓的編號是多少

這題本人做法略微有些復雜,使用了分塊+雙端隊列

將每 \(\sqrt n\) 只熊貓裝在一個塊內,每只熊貓維護一下當前它所在的塊。當熊貓 \(i\) 走到隊首時,我們可以對於熊貓 \(i\) 所在的塊內暴力刪除這個熊貓,再把它加到開頭那個分塊內。接着,從它原先在的塊開始,把前一個塊的最后一個彈出,扔進當前塊內。記得在處理時更新一下被改動的熊貓所在的塊。走到隊尾也是類似的處理。

由於原先所在塊內有 \(\sqrt n\) 只熊貓,暴力刪除的復雜度是 \(O(\sqrt n)\) 的;對外每塊末尾扔進后一個塊,單次處理是 \(O(1)\) 的,總的次數是 \(O(\sqrt n)\) 次。因此修改的復雜度是 \(O(\sqrt n)\) 的。

查詢當前第 \(i\) 只熊貓,可先從分塊外掃過去,直到掃到查詢熊貓所在分塊;在進入分塊暴力查詢;也可直接用公式算出在第幾個分塊,然后進入暴力查詢。

外面掃分塊的復雜度為 \(O(\sqrt n)\) ,用公式直接算出在哪個分塊是 \(O(1)\) 的;分塊內暴力查詢的復雜度是 \(O(\sqrt n)\) 的。因此查詢的復雜度是 \(O(\sqrt n)\) 的。

因此,總復雜度為 \(O(q\sqrt n)\) 。過不了就卡卡常數。

【代碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
typedef deque<int> dq;
int N,Q;
struct SQRT{
    dq DQ;
    inline void insertBack(int val) { DQ.push_back(val); }
    inline void insertFront(int val) { DQ.push_front(val); }
    inline int popBack(){
        int res=DQ.back();
        DQ.pop_back();
        return res;
    }
    inline int popFront(){
        int res=DQ.front();
        DQ.pop_front();
        return res;
    }
    inline void popElem(int val){
        dq::iterator p=DQ.begin();
        while(*p!=val) p++;
        DQ.erase(p);
    }
    inline int ans(int pos){
        for(auto e : DQ)
            if(pos) pos--;
            else return e;
    }
};
struct MAIN{
    int Siz;
    int Cnt;
    int Set[MAXN];
    SQRT S[500];
    inline void Front(int val){
        int pos=Set[val],res;
        S[pos].popElem(val);
        for(int i=pos;i>0;i--){
            res=S[i-1].popBack();
            Set[res]=i;
            S[i].insertFront(res);
        }
        S[0].insertFront(val);
        Set[val]=0;
    }
    inline void Back(int val){
        int pos=Set[val],res;
        S[pos].popElem(val);
        for(int i=pos;i<Cnt;i++){
            int res=S[i+1].popFront();
            Set[res]=i;
            S[i].insertBack(res);
        }
        S[Cnt].insertBack(val);
        Set[val]=Cnt;
    }
    inline int ans(int pos){
        int Tot=0;
        for(int i=0;i<=Cnt;i++)
            if(pos>=Tot&&pos<Tot+Siz) return S[i].ans(pos-Tot)+1;
            else Tot+=Siz;
    }
}M;
inline void pre(){
    cin>>N>>Q;
    M.Siz=floor(sqrt(N));
    M.Cnt=(N-1)/M.Siz;
    for(int i=0;i<N;i++)
        M.S[i/M.Siz].insertBack(i),M.Set[i]=i/M.Siz;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    pre();
    int T,I;
    while(Q--&&cin>>T>>I)
        if(0);
        else if(T==1) M.Front(I-1);
        else if(T==2) M.Back(I-1);
        else if(T==3) cout<<M.ans(I-1)<<endl;
    return 0;
}

  1. 有一棵 \(n\) 個點,編號分別為 \(1\)\(n\) 的樹,其中 \(s\) 號點為根。
    在樹上養了很多松鼠,在第 \(i\) 個點上住了 \(A\) 個雄松鼠,\(B\) 個雌松鼠。
    因為某些緣故,它們開始同時向根節點移動,但它們相當不安分,如果在同一個節點上,雄松鼠會和雌松鼠繁殖,簡單地來說以下事件會依序發生:
    這個點的 \(A\) 數量變成了 \(A+c\times B\),這個點的 \(B\) 數量變成了 \(B+d\times A\)
    根節點的所有松鼠移動到地面,位於地面上的松鼠不會再繁殖;
    所有松鼠同時朝它們的父節點移動。
    所有事件各自都在一瞬間完成,直至樹上沒有松鼠。
    現在想知道最終有多少只松鼠到達了地面。

題目有一些問題,理論上當 \(A,B\) 一位為 \(0\) 時,是不會繁殖的。但這題視為會繁殖,那就這樣處理吧。

遍歷一遍整棵樹,不難發現,每個節點的松鼠只會遇到同一層的松鼠。而且根據分配律可證明(先挖坑,自己還沒想明白),不論同一層的松鼠怎么分配,它們最后對答案的貢獻;即為它們的和,乘上層數次(根節點為 \(1\) 層)的矩陣 \(\left( \begin{matrix} 1&C \\\ \\ D&1 \end{matrix} \right)\)

即第 \(n\) 層對答案的貢獻為 \(\left( \begin{matrix} 1&C \\\ \\ D&1 \end{matrix} \right)^n\cdot \left( \begin{matrix} \displaystyle \sum_{dep_i=n}A_i \\\ \\ \displaystyle \sum_{dep_i=n}B_i \end{matrix} \right)\)

預處理出每一層對總和 \(A,B\) 的貢獻,矩陣的乘方可以遞推,累加起來即是答案。

【代碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7,MAXN=1e5+10;
struct Matrix{
    ll Num[2][2];

    Matrix() { Num[0][0]=Num[0][1]=Num[1][0]=Num[1][1]=0; }
    Matrix operator * (const Matrix &x) const {
        Matrix y;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                for(int k=0;k<2;k++)
                    y.Num[i][j]=(y.Num[i][j]+Num[i][k]*x.Num[k][j])%MOD;
        return y;
    }
    Matrix operator + (const Matrix &x) const {
        Matrix y;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                y.Num[i][j]=(Num[i][j]+x.Num[i][j])%MOD;
        return y;
    }
}Bas,Dep[MAXN],Mul,Ans;
ll N,S,C,D,A[MAXN],B[MAXN];
vector<int> Edg[MAXN];
void dfs(int pos,int pa,int fl){
    Dep[fl].Num[0][0]+=A[pos];
    Dep[fl].Num[1][0]+=B[pos];

    for(auto to : Edg[pos])
        if(to!=pa)
            dfs(to,pos,fl+1);
}
inline void pre(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>N>>S>>C>>D;
    for(int i=1;i<N;i++){
        int u,v;
        cin>>u>>v;
        Edg[u].push_back(v);
        Edg[v].push_back(u);
    }
    for(int i=1;i<=N;i++) cin>>A[i]>>B[i];
    Bas.Num[0][0]=1;
    Bas.Num[0][1]=C;
    Bas.Num[1][0]=D;
    Bas.Num[1][1]=1;
    Mul.Num[0][0]=1;
    Mul.Num[1][1]=1;
    dfs(S,0,1);
}
int main(){
    pre();
    for(int i=1;i<=N;i++){
        Mul=Mul*Bas;
        Ans=Ans+Mul*Dep[i];
    }
    cout<<(Ans.Num[0][0]+Ans.Num[1][0])%MOD<<endl;
    return 0;
}

  1. 有一個碗狀容器高度為 \(H\) ,容器厚度不計,用任一平行於底的水平平面截取碗得到的都是圓,且半徑 \(r(h)\) 滿足: \(r(h)=r_​0+e^h,h\in [0,H]\)
    其中 \(h\) 為水平截面到底部的距離,\(e\) 為自然對數。
    給定 \(k\) ,求使得容器恰好儲水總容量的 \(​{1\over k}\)​​​ 時的水面高度 \(h_k\)

不難列出方程 \(\displaystyle {1\over k}\int_0^H\pi r^2(h)\text dh=\int_0^{h_k}\pi r^2(h)\text dh\)

令變上限函數 \(\displaystyle f(x)=\int_0^x r^2(h)\text dh\) 則不難整理出 \({1\over k}f(H)=f(h_k)\)

由於 \(f'(x)=r^2(x)\geq 0\)\(f(x)\) 單調遞增,可以二分

又因為 \(\displaystyle f(x)=\int_0^x (r_0+e^h)^2\text dh=({1\over 2}e^{2h}+2r_0e^h+r_0^2h)|^x_0={1\over 2}(e^{2x}-1)+2r_0(e^x-1)+r_0^2x\) 其他的就二分可出答案

當然,由於精度要求較低,且 \([0,H]\) 枚舉范圍較小,可以直接 for 循環處理

【代碼】

#include<bits/stdc++.h>
using namespace std;
const double esp=1e-6;
double r0,H,K;
inline double f(double x){
    return 0.5*(exp(2*x)-1)+(exp(x)-1)*2*r0+r0*r0*x;
}
int main(){
    cin>>r0>>H>>K;
    double Y=f(H)/K;
    double Head=0,Tail=H,Mid,Ans=0;
    while(Tail-Head>esp){
        Ans=Mid=(Head+Tail)/2;
        double y=f(Mid);
        if(y>Y) Tail=Mid;
        else Head=Mid;
    }
    printf("%0.2f",Ans);
    return 0;
}

  1. \(n\) 個人(編號 \([1,n]\) ),每個人說了一句話。第 \(i\) 個人說話內容為 \(j,v\) ,當 \(v=1\) 表示第 \(i\) 個人說第 \(j\) 個人說的是真話,若 \(v=0\) 表示說的是假話,若 \(v=−1\) 表示第 \(i\) 個人說不知道第 \(j\) 個人的話是真還是假。
    \(n\) 個人說的句話,每個人說的要么是真的,要么是假的,問共有多少種不同的可能?由於答案很大,請將答案對 \(k\) 取模

類似於食物鏈。當 \(v_i=1\) 時,分別連接 \(i,j_i\)\(\neg i,\neg j_i\) ;表示若第 \(i\) 個人說的是真話,則第 \(j_i\) 個人說的是真話;若第 \(i\) 個人說的是假話,則第 \(j_i\) 個人說的是假話。

同理,當 \(v_i=0\) 是,分別連接 \(i,\neg j_i\)\(\neg i,j_i\)\(v_i=-1\) 的不處理。

則若存在 \(i\) 使得 \(i,\neg i\) 處於同一並查集內,一定無解。一個人不能既說真話,又說假話。此時返回 \(0\)

否則,若第 \(i\) 個人說了真話,則所有與它處於同一並查集的情況都應視為成立。故統計總並查集的數量 \(Cnt\) ,答案即為 \(2^{Cnt\over 2}\) (每個人說真話和說假話都會統計到一次)

【代碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=2e6+10;
ll N,K;
inline ll fpow(ll a,ll x){
    ll ans=1;
    for(;x;x>>=1,a=a*a%K) if(x&1) ans=ans*a%K;
    return ans;
}
ll Pa[MAXN],Vis[MAXN];
int pa(int n) { return (n==Pa[n])?n:(Pa[n]=pa(Pa[n])); }
inline void merge(int u,int v) { Pa[pa(u)]=pa(v); }
inline bool isunion(int u,int v) { return pa(u)==pa(v); }
inline void pre(){
    cin>>N>>K;
    ll J,V;
    for(int i=1;i<=N+N;i++) Pa[i]=i,Vis[i]=0;
    for(int i=1;i<=N;i++){
        cin>>J>>V;
        if(V==-1) continue;
        else if(V==1) merge(i,J),merge(i+N,J+N);
        else if(V==0) merge(i+N,J),merge(i,J+N);
    }
}
inline ll ans(){
    ll Cnt=0;
    for(int i=1;i<=N;i++)
        if(isunion(i,i+N)) return 0;
        else if(!Vis[pa(i)]){
            Vis[pa(i)]=1;
            Vis[pa(i+N)]=1;
            Cnt++;
        }
    return fpow(2,Cnt);
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    pre();
    cout<<ans()<<endl;
    return 0;
}

  1. 白熊有一個長度為 \(n\) 的數組 \(a_​1,a_​2,\cdots ,a_n\)
    白熊覺得這個數組的長度太短了,所以白熊想要在這個數組的末尾再添加 \(m\) 個數。
    白熊覺得只是添加 \(m\) 個數太無聊了,它希望數組在添加了 \(m\) 個數之后,包含的本質不同的非空子序列盡可能多。
    白熊只認識從 \(1\)\(k\)\(k\) 個整數,因此數組中原有的 \(n\) 個數與將要添加的 \(m\) 個數均為不超過 \(k\) 的正整數。
    白熊希望你告訴它,在添加了 \(m\) 個數后,新數組最多可以包含多少個本質不同的非空子序列,你只需要告訴它答案對 \(1000000007\) 取模后的結果。
    一個數組的非空子序列是指將這個數組中的某些數刪去后(可以不刪,但不能全部刪去),剩下的數構成的序列。對於兩個序列 \(p,q\) , 它們本質相同當且僅當 \(p,q\) 長度相等且對於所有下標 \(i\) 滿足 \(p_​i=q_​i\)
    比如,數組 \([1,3,3]\) 的非空子序列有7個: \([1], [3], [3], [1,3], [1,3], [3,3], [1,3,3]\) ,本質不同的非空子序列有5個: \([1], [3], [1,3], [3,3], [1,3,3]\)

考慮 \(dp_n\) 表示僅使用前 \(n\) 個數(可不全使用),構成的本質非空子序列數個數。

先考慮 \(m=0\) 的情況:

則若當前數字 \(a_n\) 未出現過,則 \(dp_n=2dp_{n-1}+1\) :之前的每個非空序列都對 \(dp_n\) 有貢獻,大小為 \(dp_{n-1}\) ;后接數字 \(a_n\) 也對 \(dp_n\) 有貢獻,大小為 \(dp_{n-1}\) ;再考慮上數字 \(a_n\) 自己作為一個子序列,會與之前的序列均不同,貢獻為 \(1\)

若當前數字 \(a_n\) 出現過,設之前最后一次的出現位置為 \(lst_{a_n}\) ,則對 \(dp_n\) 的貢獻可理解為 \(2dp_{n-1}+1\) 扣去重復的部分:數字 \(a_n\) 自己作為子序列的,與前面的重復了,扣除 \(1\) ;還有需要扣除的,就是前 \((lst_{a_n}-1)\) 個位置的非空子序列,后接當前數字 \(a_n\) 的序列重復,故再扣除 \(dp[lst_{a_n}-1]\)

總結一下公式:若初始化 \(lst_{num}=0\)

\(dp_n=\begin{cases} 2dp_{n-1}+1,lst_{a_n}=0 \\\ \\ 2dp_{n-1}-dp[lst_{a_n}-1],lst_{a_n}\neq 0 \end{cases}\)

這里可以發現:若 \(dp_{1\cdots (n-1)}\) 單調遞增,若 \(a_n\) 未出現過,則 \(dp_n=2dp_{n-1}+1>dp_{n-1}\) ;若 \(a_n\) 出現過,則 \(dp_n=2dp_{n-1}-dp[lst_{a_n}-1]>dp_{n-1}+dp_{n-1}-dp_{n-1}=dp_{n-1}(lst_{a_n}<n-1\Rightarrow dp[lst_{a_n}-1]<dp[n-1-1]<dp[n-1])\)

又因為 \(dp_0=0,dp_1=2dp_0+1=1>dp_0\) ,故數學歸納法得序列 \(dp_{1\cdots n}\) 單調遞增。

接下來我們考慮 \(m\neq 0\) 的情況:

由上面式子易得,若 \(a_n\) 未出現過,則對 \(dp_n\) 的貢獻一定更大。故我們優先選擇填塗未出現過的元素。

\([1,k]\) 均出現過,則轉移方程退化為 \(dp_n=2dp_{n-1}-dp[lst_{a_n}-1]\) 。顯然 \(dp[lst_{a_n}-1]\) 越小則對 \(dp_n\) 的貢獻越大。因此我們每次需要求出最小的 \(lst_{a_n}\) ,之后我們填塗 \(a_n\) ,那么 \(lst_{a_n}\) 更新為當前的 \(n\)

因此,我們只需要用堆維護 \(lst_{a_{1\cdots k}}\) ,每次彈出最小值參加轉移方程,之后重新插入 \(n\) 即可。

【代碼】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7,MAXN=2e5+10;
ll N,M,K,A,Dp[MAXN<<1],Lst[MAXN];
priority_queue<ll> pq;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>N>>M>>K;
    for(int i=1;i<=N;i++){
        cin>>A;
        if(Lst[A])
            Dp[i]=(Dp[i-1]*2-Dp[ Lst[A]-1 ])%MOD;
        else Dp[i]=(Dp[i-1]<<1|1)%MOD;
        Lst[A]=i;
    }
    for(int i=1;i<=K;i++) pq.push(-Lst[i]);
    for(int j=1,i=N+1;j<=M;j++,i++){
        if(pq.top())
            Dp[i]=(Dp[i-1]*2-Dp[ -pq.top()-1 ])%MOD;
        else Dp[i]=(Dp[i-1]<<1|1)%MOD;
        pq.pop();
        pq.push(-i);
    }
    cout<<(Dp[N+M]+MOD)%MOD<<endl;
    return 0;
}

  1. 給定 \(n\) ,和 \(n\) 個非負整數構成序列 \(a[1\cdots n]\)
    對於序列 \(a\) ,定義集合 \(S(a)\) 表示序列 \(a\) 生成的集合,通過以下步驟任意多次:
    1.初始,\(S(a)={a_i},i\in [1,n]\)
    2.若存在 \(x,y\in S(a)\) ,但是 \(x\oplus y\not\in S(a)\) ,將其插入到 \(S(a)\)
    定義一個集合S和非負整數x的或運算和與運算分別為:
    \(S∣x=\{y∣x ∣ y\in S\}, S\&x=\{y\&x ∣ y\in S\}\)
    \(q\) 組詢問,每組詢問為以下兩種類型之一:
    \(1\) \(L\) \(R\),令\(f_​1(x)=S∣x\) ,求當 \(x\in [L,R]\) 時,本質不同的 \(f_​1(x)\) 的個數,即求: \(∣\{f_​1(x)∣x\in [L,R]\}∣\)
    \(2\) \(L\) \(R\), 令\(f_​2(x)=S\&x\) ,求當 \(x\in [L,R]\) 時,本質不同的 \(f_​2(x)\) 的個數,即求: \(∣\{f_​2(x)∣x\in [L,R]\}∣\)

現證明,對於第一種詢問,答案一定為 \((R-L+1)\)

對於 \(\forall x_1\neq x_2\) ,考慮是否 \(f_1(x_1)=f_1(x_2)\)

很顯然 \(x=0|x\in S|x=f_1(x)\)

\(x_2\not\in f_1(x_1)\) 又因為 \(x_2\in f(x_2)\)\(f(x_1)\neq f(x_2)\)

\(x_2\in f_1(x_1)\) ,我們將 \(x\) 視為它二進制位的集合。例如 \(9=1001_{(2)}\) 可視為集合 \(\{0,3\}\) 。為方便描述,記為 \(\boldsymbol 9=\{0,3\}\) 。那么此時,必然有 \(\boldsymbol {x_1}\subset \boldsymbol{x_2}\) 。否則,不妨設 \(a\in \boldsymbol{x_1},a\not\in \boldsymbol{x_2}\) ,則對於 \(\forall n \in f_1(x_1),\exist t\in S\) 使得 \(n=t|x_1\)
\(\boldsymbol{n}=\boldsymbol{t}\cup \boldsymbol{x_1}\)\(a\in \boldsymbol{n}\) 恆成立。因為 \(x_2\in f_1(x_1)\) ,故 \(a\in \boldsymbol{x_2}\) ,與假設矛盾。

因此 \(\boldsymbol{x_1}\subset \boldsymbol{x_2}\) 又因為 \(x_1\neq x_2\)\(\exist a\not\in \boldsymbol{x_1},a\in \boldsymbol{x_2}\) 。此時同上可得 \(\forall n\in f_1(x_2)\) 都有 \(a\in \boldsymbol{n}\) 。因此可得 \(x_1\not\in f_1(x_2)\) 。又因為 \(x_1\in f_1(x_1)\)\(f_1(x_1)\neq f_1(x_2)\)

綜上,對於 \(\forall x_1\neq x_2,f(x_1)\neq f(x_2)\) ,故對於不同的 \(x\in[L,R]\)\(f_1(x)\) 並不相同。因此 \(|\{f_1(x)|x\in [L,R]\}|=|\{x|x\in [L,R]\}|=R-L+1\)

對於 \(\forall x_1,x_2\) ,我們考慮何時有 \(f_2(x_1)\neq f_2(x_2)\)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM