• POI题目选做


    POI题目选做

    [POI2015]WIL-Wilcze doły

    题意

    给定一个长度为 n 的序列,你有一次机会选中一段连续的长度不超过 d 的区间,将里面所有数字全部修改为 0。请找到最长的一段连续区间,使得该区间内所有数字之和不超过 p

    题解

    显然长度为D时只会更优,尺取法枚举,单调队列维护被删除的一段

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long
    
    inline LL read()
    {
        LL f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 2000000 + 5;
    
    LL n,p,d;
    LL sum[MAXN],a[MAXN];
    LL ans;
    LL q[MAXN],head = 1,tail;
    
    inline LL calc(LL x)
    {
        return sum[x] - sum[x-d];    
    } 
    
    int main()
    {
        n = read(),p = read(),d = read();
        for(int i=1;i<=n;i++) a[i] = read(),sum[i] = sum[i-1] + a[i];
        ans = d;
        q[++tail] = d;
        int l = 1;
        for(int i=d+1;i<=n;i++)
        {
            while(head <= tail && calc(i) > calc(q[tail])) tail--;
            q[++tail] = i;
            while(head <= tail && sum[i] - sum[l-1] - calc(q[head]) > p) 
            {
                l++;
                while(head <= tail && l >q[head] - d + 1) head++;    
            }
            ans = max(ans, 1LL * i - l + 1);  
         } 
         cout << ans << endl;
    }
    View Code

    [POI2012]LIT-Letters

    题意

    给出两个长度相同的的只含大写字母的字符串 a,b

    每次可以交换相邻字符,求a到b的最小交换次数

    题解

    火柴排队弱化版?

    显然逆序对

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long
    
    inline LL read()
    {
        LL f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 1000000 + 5;
    
    int n;
    char s[MAXN];
    int a[MAXN];
    queue<int>Q[30];
    LL c[MAXN];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    
    inline LL Query(LL x)
    {
        LL res = 0;
        while(x)
        {
            res += c[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    inline void update(int x,int v)
    {
        while(x <= n)
        {
            c[x] += v;
            x += lowbit(x);
        }
    }
    
    int main()
    {
        n = read();
        scanf("%s",s+1);
        for(int i=1;i<=n;i++) a[i] = s[i]  - 'A';
        scanf("%s",s+1);
        for(int i=1;i<=n;i++) Q[s[i] -'A'].push(i);
        for(int i=1,cur;i<=n;i++) cur = a[i],a[i] = Q[cur].front(),Q[cur].pop();
        LL ans = 0;
        for(int i=1;i<=n;i++)
        {
            ans += i - 1 - Query(a[i]);
            update(a[i],1);
        }
        cout << ans << endl;
    }
    View Code

     

    [POI2013]LUK-Triumphal arch

    题意

    给一颗树,1号节点已经被染黑,其余是白的,两个人轮流操作,一开始B在1号节点,A选择k个点染黑,然后B走一步,如果B能走到A没染的节点则B胜,否则当A染完全部的点时,A胜。

    求能让A获胜的最小的k

    题解

    显然二分答案

    考虑树形DP检验

    显然只需要考虑再子树i中最多需要染几次色

    把儿子不够的染色次数合并上来即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long
    
    inline LL read()
    {
        LL f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 3e5 + 10;
    
    int n,ans;
    vector<int>G[MAXN];
    int dp[MAXN];
    
    inline void dfs(int x,int f,int mid)
    {
        int sz = 0;
        for(int i=0;i<G[x].size();i++)
        {
            int v = G[x][i];
            if(v == f) continue;
            dfs(v,x,mid);
            sz++;
            dp[x] += dp[v];        
        }
        dp[x] = max(0,dp[x]+sz-mid);
    }
    
    inline bool check(int mid)
    {
        memset(dp,0,sizeof(dp));
        dfs(1,0,mid);
        if(dp[1] == 0) return true;
        else return false;
    }
    
    int main()
    {
        n = read();
        for(int i=1;i<n;i++)
        {
            int u = read(),v =read();
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int l = 0,r = n;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(check(mid))
            {
                r = mid - 1;
                ans = mid;
            }
            else l = mid + 1;
        }
        cout << ans << endl;
    }
    View Code
  • 相关阅读:
    数据仓库基础(十四)缓慢变化维
    数据仓库基础(十三)Informatica workflow
    数据仓库基础(十二)Informatica组件(2)
    数据仓库基础(十一)Informatica小技巧(2)
    数据仓库基础(十)组件1
    数据仓库基础(九)Informatica小技巧(1)
    数据仓库基础(八)Informatica 小例子
    数据仓库基础(七)Informatica PowerCenter介绍
    数据仓库基础(六)数据的ETL
    数据仓库基础(五)数据仓库系统应用实例
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/14008102.html
Copyright © 2020-2023  润新知