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
  • 相关阅读:
    loaded some nib but the view outlet was not set
    指标评比
    IOS DEVELOP FOR DUMMIES
    软件测试题二
    javascript select
    DOM节点类型详解
    mysql操作
    UVA 10055
    solutions for 'No Suitable Driver Found For Jdbc'
    解决git中文乱码问题
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11785485.html
Copyright © 2011-2022 走看看