zoukankan      html  css  js  c++  java
  • cf Round 607

    A.Chain Reaction(DP+二分)

    题意:一排有n个灯塔,每个灯塔给出坐标xi和力量yi,
    每次从最右边依次点亮灯塔,每点亮一个灯塔,它左边的距离它yi范围内的灯塔将受到损坏。
    现在允许在最右边>max(xi)处添加一座力量值yi的灯塔。
    问最少只会损坏多少灯塔。

    分析:因为我们是从右边点亮灯塔的,所以我们点亮我们添加的那座灯塔只会损坏连续个灯塔。最后就相当于从末尾的某一个灯塔开始点亮。
    我们令dp[i]表示点亮第i座灯塔最少损坏多少灯塔。
    于是我们对于每个dp[i],二分可以得到他前面的前驱。
    所以dp[i]=dp[j]+1(j<i).
    注意题目给出的灯塔并不是有序的,需要排序一遍。

    # include <stdio.h>
    # include <string.h>
    # include <stdlib.h>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <math.h>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define MAXN 100005
    # define eps 1e-5
    # define MAXM 1000005
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    typedef unsigned long long ULL;
    int _MAX(int a, int b){return a>b?a:b;}
    int _MIN(int a, int b){return a>b?b:a;}
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    
    int a[100005][2], sum[100005];
    
    int comp(const void * b, const void * c){return *(int *)b-*(int *)c;}
    int main ()
    {
        int n;
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d%d",&a[i][0],&a[i][1]);
        qsort(a+1,n,sizeof(a[1]),comp);
        sum[1]=1;
        FOR(i,2,n) {
            int l=0, r=i, mid;
            while (l<r) {
                mid=(l+r)>>1;
                if (l==mid) break;
                if (a[mid][0]<a[i][0]-a[i][1]) l=mid;
                else r=mid;
            }
            sum[i]=1+sum[l];
        }
        int ans=0;
        FOR(i,1,n) ans=max(ans,sum[i]);
        printf("%d
    ",n-ans);
        return 0;
    }
    View Code

    B.Zuma(区间DP)

    给出一串n个数字(n<=500).每次操作可以消掉一个回文串。然后补齐。
    问最少需要操作多少次。

    姿势很优雅的区间DP;
    很容易想到dp[l][r]表示消掉[l,r]的回文串最少需要多少步。
    但是在转移的过程中GG了,假如它先消中间的某一部分,然后再对齐再消,这样咋办。
    于是我码了一个暴力判断字符串是否回文。结果TLE了。
    仔细一想,因为1个数字显然是回文串。
    对于[l,r]区间,我们枚举[l+1,r]内的一个k使得a[k]==a[l],这时候我们可以先消[l+1,k-1].
    再消a[l]和a[k],我们注意到消[l+1,k-1]的最后一步一定会变成一个回文串,
    因为a[l]==a[k], 所以我们消a[l,k]的步数就等于a[l+1,k-1].
    即dp[l][k]==dp[l+1][k-1].
    所以状态转移方程就是dp[l][r]=min(dp[l+1][r]+1,dp[l+1][k-1]+dp[k+1][r])(a[k]==a[l])
    最后判断一下边界就行了。

    # include <stdio.h>
    # include <string.h>
    # include <stdlib.h>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <math.h>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define MAXN 100005
    # define eps 1e-5
    # define MAXM 1000005
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    typedef unsigned long long ULL;
    int _MAX(int a, int b){return a>b?a:b;}
    int _MIN(int a, int b){return a>b?b:a;}
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    
    int n, a[505], dp[505][505];
    
    int dfs(int l, int r)
    {
        if (~dp[l][r]) return dp[l][r];
        if (l>r) return 1;
        if (l==r) return dp[l][r]=1;
        int ans=INF;
        ans=min(ans,dfs(l+1,r)+1);
        FOR(i,l+1,r) {
            if (a[i]==a[l]) {
                if (i==r) ans=min(ans,dfs(l+1,i-1));
                else if (i==l+1) ans=min(ans,dfs(i+1,r)+1);
                else ans=min(ans,dfs(l+1,i-1)+dfs(i+1,r));
            }
        }
        return dp[l][r]=ans;
    }
    int main ()
    {
        mem(dp,-1);
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i);
        dfs(1,n);
        printf("%d
    ",dp[1][n]);
        return 0;
    }
    View Code

    C.Marbles(脑洞+hash)

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 1E9+9;
    const int MI = ~0u>>1;
    
    int main()
    {
        int n;
        string s1,s2;
        cin>>n>>s1>>s2;
        n--;
        for(int i=0;i<n;i++)
        {
            switch(s2[i])
            {
                case 'N':s2[i]='S';break;
                case 'S':s2[i]='N';break;
                case 'W':s2[i]='E';break;
                case 'E':s2[i]='W';break;
            }
        }
        ULL v1=0,v2=0;
        const ULL seed=131;
        ULL wt=1;
        for(int i=n-1;i>=0;i--,wt*=131)
        {
            v1=v1+(s1[i]-'a')*wt;
            v2=v2*seed+s2[i]-'a';
            if(v1==v2)
            {
                printf("NO");
                return 0;
            }
        }
        printf("YES");
        return 0;
    }
    View Code

    D.Power Tree(线段树维护dfn+逆元)

    分析: 我们可以算出每一个节点对根节点的贡献因子mi。
    即di是节点i的儿子节点数+1.
    实际上mi就是从i到根节点的简单路径上的di的乘积。
    当新加入一个节点u到节点p时。我们观察可以发现,仅仅改变了p和p的子树的mi。
    显然是mi=mi*(dp+1)/dp. mu=mp。
    我们需要一个数据结构可以 对一个区间进行乘,更新一个值,以及求一个区间的总和。
    我们用线段树维护dfn序。
    那么一个节点的子树就是一段连续的区间。
    我们求一个节点的贡献时。显然就是sum同时除以他们的公共路径的mi。
    由于乘法是一个浮点数。我们先累乘所有的分子,再累乘所有的分母,最后我们用乘法逆元
    可以求出取模。

    代码量有点受不了。。。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #pragma comment(linker, "/STACK:16000000")
    using namespace std;
    
    typedef long long ll;
    
    const int mod = 1000000007;
    const int Maxn = 200005;
    const int Maxm = 1048576;
    
    int n, q;
    int val[Maxn];
    int a[Maxn], b[Maxn], c[Maxn];
    vector <int> neigh[Maxn];
    int ch[Maxn];
    int P[Maxn], cur, L[Maxn], R[Maxn];
    int mult[Maxm];
    int fl[Maxm], sum[Maxm];
    
    void Traverse(int v)
    {
        L[v] = ++cur;
        for (int i = 0; i < neigh[v].size(); i++)
            Traverse(neigh[v][i]);
        R[v] = cur;
    }
    
    void createMult(int v, int l, int r)
    {
        mult[v] = 1;
        if (l < r) {
            int m = l + r >> 1;
            createMult(2 * v, l, m); createMult(2 * v + 1, m + 1, r);
        }
    }
    
    void updMult(int v, int l, int r, int a, int b, int val)
    {
        if (l == a && r == b) mult[v] = ll(mult[v]) * val % mod;
        else {
            int m = l + r >> 1;
            if (a <= m) updMult(2 * v, l, m, a, min(m, b), val);
            if (m + 1 <= b) updMult(2 * v + 1, m + 1, r, max(m + 1, a), b, val);
        }
    }
    
    int getMult(int v, int l, int r, int x)
    {
        int res = mult[v];
        if (l < r) {
            int m = l + r >> 1;
            if (x <= m) res = ll(res) * getMult(2 * v, l, m, x) % mod;
            else res = ll(res) * getMult(2 * v + 1, m + 1, r, x) % mod;
        }
        return res;
    }
    
    void Union(int v)
    {
        sum[v] = (sum[2 * v] + sum[2 * v + 1]) % mod;
    }
    
    void downOn(int v, int val)
    {
        fl[v] = ll(fl[v]) * val % mod;
        sum[v] = ll(sum[v]) * val % mod;
    }
    
    void Down(int v)
    {
        if (fl[v] != 1) {
            downOn(2 * v, fl[v]); downOn(2 * v + 1, fl[v]);
            fl[v] = 1;
        }
    }
    
    void createSum(int v, int l, int r)
    {
        fl[v] = 1;
        if (l == r) sum[v] = val[l];
        else {
            int m = l + r >> 1;
            createSum(2 * v, l, m); createSum(2 * v + 1, m + 1, r);
            Union(v);
        }
    }
    
    int getSum(int v, int l, int r, int a, int b)
    {
        if (l == a && r == b) return sum[v];
        else {
            Down(v);
            int m = l + r >> 1;
            int res = 0;
            if (a <= m) res = (res + getSum(2 * v, l, m, a, min(m, b))) % mod;
            if (m + 1 <= b) res = (res + getSum(2 * v + 1, m + 1, r, max(m + 1, a), b)) % mod;
            return res;
        }
    }
    
    void multSum(int v, int l, int r, int a, int b, int val)
    {
        if (l == a && r == b) downOn(v, val);
        else {
            Down(v);
            int m = l + r >> 1;
            if (a <= m) multSum(2 * v, l, m, a, min(m, b), val);
            if (m + 1 <= b) multSum(2 * v + 1, m + 1, r, max(m + 1, a), b, val);
            Union(v);
        }
    }
    
    void addSum(int v, int l, int r, int x, int val)
    {
        if (l == r) sum[v] = val;
        else {
            Down(v);
            int m = l + r >> 1;
            if (x <= m) addSum(2 * v, l, m, x, val);
            else addSum(2 * v + 1, m + 1, r, x, val);
            Union(v);
        }
    }
    
    int Inv(int a)
    {
        int p = mod - 2;
        int res = 1;
        while (p) {
            if (p & 1) res = ll(res) * a % mod;
            p >>= 1; a = ll(a) * a % mod;
        }
        return res;
    }
    
    int main()
    {
        n = 1; scanf("%d %d", &val[n], &q);
        for (int i = 0; i < q; i++) {
            scanf("%d %d", &a[i], &b[i]);
            if (a[i] == 1) {
                scanf("%d", &c[i]);
                n++; P[n] = b[i];
                neigh[b[i]].push_back(n);
            }
        }
        Traverse(1);
        createMult(1, 1, R[1]);
        createSum(1, 1, R[1]);
        n = 1;
        for (int i = 0; i < q; i++)
            if (a[i] == 1) {
                n++;
                ch[b[i]]++;
                int tomult = ll(ch[b[i]] + 1) * Inv(ch[b[i]]) % mod;
                updMult(1, 1, R[1], L[b[i]], R[b[i]], tomult);
                multSum(1, 1, R[1], L[b[i]], R[b[i]], tomult);
                val[n] = c[i];
                tomult = getMult(1, 1, R[1], L[n]);
                addSum(1, 1, R[1], L[n], ll(tomult) * val[n] % mod);
            } else {
                int res = getSum(1, 1, R[1], L[b[i]], R[b[i]]);
                if (P[b[i]]) {
                    int tomult = Inv(getMult(1, 1, R[1], L[P[b[i]]]));
                    res = ll(res) * tomult % mod;
                }
                printf("%d
    ", res);
            }
        return 0;
    }
    View Code

    E.Cross Sum(待填坑)

  • 相关阅读:
    关于WP7的Loaded事件[转]
    皮皮书屋的变态验证码
    近期学习内容for mobile
    一个js问题引发的同时吐槽
    powerdesigner 概念模型转物理模型时的丢表问题
    偶的处女文近期学习计划
    web布局实现圆角,兼容所有的浏览器
    最近面试asp.net碰到的一些题
    网站推广心得
    兼容ie6的png格式图片的背景透明问题
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6255967.html
Copyright © 2011-2022 走看看