zoukankan      html  css  js  c++  java
  • HGOI 20191103am 题解

    Problem A number

        使用一个$2^k$数集中每个元素的和表示数$n$,不同集合的数目有多少?

        对于$100\%$的数据满足$1 leq n leq 10^6$

      Solution : 

      $f[i][j]$表示使用不大于$2^i$的数组成集合,构成数$j$的不同集合数目。

      利用完全背包的思想,一开始$f[i+1][j] = f[i][j] + sum_{k} f[i][j-k * 2^{i+1}]$

      显然可以通过滚动数组来优化,利用完全背包的思想,我们得到如下算法:

      一开始令$f[i+1][j] = f[i][j]$,然后从小到大考虑每一个$j$,用$f[i+1][j] += f[i+1][j-2^{i+1}]$的dp方程转移。

      时间复杂度$O(n log_2 n)$

    # include<bits/stdc++.h>
    # define int long long
    # define MOD(x) ((x>=mo)?(x-mo):(x)) 
    using namespace std;
    const int N=1e6+10;
    const int mo=1000000007;
    int n,f[N];
    signed main() {
        scanf("%lld",&n); f[0]=1;
        for (int i=0;(1<<i)<=n;i++) 
            for (int j=0;j<=n;j++)
                if (j>=(1<<i)) f[j]=MOD(f[j]+f[j-(1<<i)]);
        printf("%lld
    ",f[n]%mo);
        return 0;
    }
    number.cpp

    Problem B game

      有$n$个变量$x_1,x_2,...,x_n$,并给出$d$, 现在有$m$个限制$(a,b)$,满足$|x_a - x_b| leq d$ 

      求出$max{x_1,x_2,...,x_n} - min{x_1,x_2,...,x_n}$的最大值,且满足上述限制。

      对于$100\%$的数据满足$nleq 500$

      Solution : 

        首先答案一定是$d$的倍数,所以我们只需要将每一条边权变为$1$,来考虑这个问题。

        将每一条限制建图,我们不妨考虑从点$i$开始到点$i$结束的一个环。

        显然,要让这个环上的点都满足条件,其权值最大的点必然是这个环的中点。

        这个中点的权值,等价于从$i$为源点,到所有目标点$j$最短路的最大值。

        考虑不在这个环上的所有边,必然可以构造出一种合法状态使整个图满足条件。

        所以,本题的答案和求出这个图中最短路的最大值等价。

        直接用$floyd$即可,时间复杂度为$O(n^3)$

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int f[55][55];
    int d;
    int solve(){
        cin >> n; cin >> d;
        for (int i=1;i<=n;i++){
            for (int j=1;j<=n;j++){
                char c;
                cin >> c;
                if (c == 'N') f[i][j] = 0x3f3f3f3f;
                else f[i][j] = 1;
                if (i == j) f[i][j] = 0;
            }
        }
        for (int k=1;k<=n;k++)
            for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++)
                    f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
        
        int ans = 0;
        for (int i=1;i<=n;i++){
            for (int j=1;j<=n;j++)
                ans = max(ans, f[i][j]);
        }
        if (ans > 100000) cout << -1 << endl;
        else cout << (long long)ans * d << endl;
    }
    
    int main(){
    //  freopen("bridge.in","r",stdin);
    //  freopen("bridge.out","w",stdout);
        int T;
        cin >> T;
        while (T--){
            solve();
        }
    }
    game.cpp

    Problem C queue

      有一个$[1,n]$的排列,每一次可以将一个数移到排列的头部或者尾部。

       求出最小操作次数使得排列有序。

       对于$100\%$的数据满足$1 leq nleq 10^5$

      Solution : 

        本题有一个加强版$CF1223D$. (可以把那个代码粘贴过来,然后就A掉了)

        还是重新考虑这个弱化版本,甚至还不需要用离散化。

        一个答案的构造一定满足$l,l-1,l-2,...,1$依次放到队首,$r,r+1,...,n$依次放到队尾。

        于是我们可以$dp$,设$dp[i]$表示$i$之前的最长的长度,使得$i - dp[i]+1, i-dp[i] , ... i$这些数有序。

        那么最后的答案必然是$n - max(dp[i])$

        对于本题,等价于求出n - 连续最长上升子序列,时间复杂度为$O(n)$

    # include <bits/stdc++.h>
    using namespace std;
    const int N=3e5+10;
    int n,a[N],dp[N],MinID[N],MaxID[N];
    vector<int>tmp;
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    int main()
    {
        int T=1; 
        while (T--) {
            tmp.clear();
            n=read();
            for (int i=1;i<=n;i++) {
                a[i]=read();
                tmp.push_back(a[i]);
            }
            sort(tmp.begin(),tmp.end());
            tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
            for (int i=1;i<=n;i++) {
                a[i] = lower_bound(tmp.begin(),tmp.end(),a[i]) - tmp.begin() + 1;
            }
            int sz = tmp.size();
            for (int i=1;i<=sz;i++) MinID[i]=0x3f3f3f3f,MaxID[i]=-0x3f3f3f3f; 
            for (int i=1;i<=n;i++) {
                MinID[a[i]] = min(MinID[a[i]],i);
                MaxID[a[i]] = max(MaxID[a[i]],i);
            }   
            dp[1]=1; int ans = sz-1;
            for (int i=2;i<=sz;i++) {
                if (MaxID[i-1] < MinID[i]) dp[i]=dp[i-1]+1;
                else dp[i]=1;
                ans = min(ans,sz-dp[i]);
            }
            printf("%d
    ",ans); 
        } 
        return 0;
    }
    CF1223D
    # include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int n,p[N],a[N],f[N],ans;
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]]=i;
        for (int i=1;i<=n;i++) {
            f[i]=1;
            if (p[a[i]-1]<i) f[i] = max(f[i],f[p[a[i]-1]]+1);
            ans = max(ans,f[i]); 
        }
        printf("%d
    ",n-ans);
        return 0;
    }
    queue.cpp
  • 相关阅读:
    【学习总结】 小白CS成长之路
    Java程序员面试题收集(1)
    ECSTORE2.0 去页面底部版权
    vue-cli安装
    linux下安装nodejs
    Access denied for user 'root'@'localhost' (using password: YES)的解决
    想说的话
    十三:CSS之CSS的四种使用方法和优先级
    十二:CSS之基础语法
    十一:HTML之实现基本网页结构
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11785485.html
Copyright © 2011-2022 走看看