zoukankan      html  css  js  c++  java
  • 8.7 Round 2

     刚说完白天思维性弱,晚上就来三道思维题...

    T1:https://www.luogu.org/problem/T92604

    规律没找出来,35pts打表滚粗

    可以证明(我也不会),p=a^3+3a+1

    在a=871时,p>2e9,所以枚举a,然后sqrt(L)判p是否是质数即可

    T2:https://www.luogu.org/problem/T92605

    考场上想了一想,觉得sum不好维护,于是就暴力了...

    题目中给的y = -1或1,就保证了,对一个数进行修改,只会影响它前后一位的sum

    做法:统计sum[i]:<=i的数的个数和,num[i],=i的数的个数和

    然后对于一个数,它不可以删,当且仅当num[i] != 0 && sum[i] != i

    记上面的答案为ok[i],线段树维护序列,于是我们获得了一个权值线段树,值为0/1

    对于询问,相当于询问1-x的最靠右1的位置,轻松维护

    对于修改,考虑几种情况就行

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<climits>
    #include<map>
    #include<queue>
    #include<cmath>
    using namespace std;
    #define O(x) cout << #x << " " << x << endl;
    #define B cout << "breakpoint" << endl;
    #define clr(a) memset(a,0,sizeof(a));
    inline int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (ans *= 10) += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    const int maxn = 5e5 + 5;
    int a[maxn],n,m,tp[maxn];
    int num[maxn],sum[maxn];
    bool ok[maxn];
    struct node
    {
        int sum,rm;
    };
    struct seg_tr
    {
        node tr[maxn << 2];
        #define ls i << 1
        #define rs i << 1 | 1
        inline node up(node i,node l,node r)
        {
            i.sum = l.sum + r.sum;
            if(r.rm) i.rm = r.rm; else i.rm = l.rm;
            return i;
        }
        void build(int i,int l,int r)
        {
            if(l == r)
            {
                if(ok[l]) tr[i] = (node){1,l};
                else tr[i] = (node){0,0};
                return;
            }
            int mid = l + r >> 1;
            build(ls,l,mid);
            build(rs,mid + 1,r);
            tr[i] = up(tr[i],tr[ls],tr[rs]);
        }
        void change(int i,int l,int r,int x,int d)
        {
            if(l == r)
            {
                tr[i].sum = d;
                if(d) tr[i].rm = l;
                else tr[i].rm = 0;
                return;
            }
            int mid = l + r >> 1;
            if(x <= mid) change(ls,l,mid,x,d);
            else change(rs,mid + 1,r,x,d);
            tr[i] = up(tr[i],tr[ls],tr[rs]);
        }
        node query(int i,int l,int r,int ql,int qr)
        {
            if(l == ql && r == qr) return tr[i];
            int mid = l + r >> 1;
            if(qr <= mid) return query(ls,l,mid,ql,qr);
            else if(ql > mid) return query(rs,mid + 1,r,ql,qr);
            else
            {
                node tr1 = query(ls,l,mid,ql,mid),tr2 = query(rs,mid + 1,r,mid + 1,qr);
                node res = up(res,tr1,tr2);
                return res;
            }
        }
    }T;
    int main()
    {
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
        n = read(),m = read();
        for(int i = 1;i <= n;i++) a[i] = read(),num[a[i]]++;
        for(int i = 1;i <= n;i++) 
        {
            sum[i] = sum[i - 1] + num[i];
            if(sum[i] != i && num[i]) ok[i] = 1;
        }
        //for(int i = 1;i <= n;i++) printf("%d ",ok[i]);
        //cout << endl;
        T.build(1,1,n);
        while(m--)
        {
            int op = read();
            if(op == 1)
            {
                int x = read();
                node ans = T.query(1,1,n,1,x);
                if(!ans.sum) { printf("0
    "); }
                else printf("%d
    ",sum[ans.rm]);
            }
            else
            {
                int x = read(),y = read();
                int p = a[x];
                a[x] += y;
                if(y == -1)
                {
                    sum[p - 1]++;
                    if(sum[p] - sum[p - 1] == 0) T.change(1,1,n,p,0);
                    if(sum[p - 1] == p - 1) T.change(1,1,n,p - 1,0);
                    else T.change(1,1,n,p - 1,1);
                }
                else
                {
                    sum[p]--;
                    if(sum[p] - sum[p - 1] == 0) T.change(1,1,n,p,0);
                    else 
                    {
                        if(sum[p] == p) T.change(1,1,n,p,0);
                        else T.change(1,1,n,p,1);
                    }
                    if(sum[p + 1] == p + 1) T.change(1,1,n,p + 1,0);
                    else T.change(1,1,n,p + 1,1);
                }    
            }
        }
    }
    /*
    6 7
    2 3 4 6 6 6
    1 6
    2 4 -1
    2 4 -1
    1 6
    1 4
    2 2 -1
    1 6
    */
         
    View Code

    T3:https://www.luogu.org/problem/T92606

    考试的时候净做这题去了,结果树dp写的不好,一看这复杂度不爆炸?于是放弃

    一开始的想法:f[u][i][j]:u及u的子树,分配i个1,号,j个2号的最多覆盖点

          那么先枚举u分配情况,再dp子树v,然后再给v分配水泵做dp,过程中临时数组记录

          第二问就二分,在分配给u水泵的时候使分配方案合法即可

    这样O(T*n*200^3*logai),GG

    然后看了标程恍然大悟

    在处理u的时候,我们可以先处理v,更新f数组

    在u的所有子树被处理完之后,最后再给u分配水泵

    加上临时数组,也很好写

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<climits>
    #include<map>
    #include<queue>
    #include<cmath>
    using namespace std;
    #define O(x) cout << #x << " " << x << endl;
    #define B cout << "breakpoint" << endl;
    #define clr(a) memset(a,0,sizeof(a));
    #define int long long
    inline int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (ans *= 10) += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    const int maxn = 25;
    const int M = 55;
    struct egde
    {
        int to,next;
    }e[maxn << 1];
    int fir[maxn],alloc;
    void adde(int u,int v)
    {
        e[++alloc].next = fir[u],fir[u] = alloc,e[alloc].to = v;
        swap(u,v);
        e[++alloc].next = fir[u],fir[u] = alloc,e[alloc].to = v;
    }
    int n,a[maxn],s1,s2,p1,p2;//p1 > p2
    int f[25][M][M],tmp[M][M];
    int mid,ans;
    void dp(int u,int fa)
    {
        for(int i = fir[u];i;i = e[i].next)
        {
            int v = e[i].to;
            if(v == fa) continue;
            dp(v,u);
            clr(tmp);
            for(int i = 0;i <= s1;i++)
                for(int j = 0;j <= s2;j++)
                    for(int x = 0;x <= i;x++)
                        for(int y = 0;y <= j;y++)
                            tmp[i][j] = max(tmp[i][j],f[u][i - x][j - y] + f[v][x][y]);
            for(int i = 0;i <= s1;i++)
                for(int j = 0;j <= s2;j++)
                    f[u][i][j] = tmp[i][j];
        }
        clr(tmp);
        for(int i = 0;i <= s1;i++)
            for(int j = 0;j <= s2;j++)
                for(int x = 0;x <= i;x++)
                    for(int y = 0;y <= j;y++)
                    if(x * p1 + y * p2 >= a[u] && x * p1 + y * p2 - a[u] <= mid)
                        tmp[i][j] = max(tmp[i][j],f[u][i - x][j - y] + 1);
        for(int i = 0;i <= s1;i++)
            for(int j = 0;j <= s2;j++)
                f[u][i][j] = tmp[i][j];
    }
    bool solve()
    {
        clr(f);
        dp(1,0);
        int res = 0;
        for(int i = 0;i <= s1;i++)
            for(int j = 0;j <= s2;j++)
                res = max(res,f[1][i][j]);
        return res == ans;
    }
    main()
    {
        freopen("system.in","r",stdin);
        freopen("system.out","w",stdout);
        int t = read();
        while(t--)
        {
            int n = read(); clr(fir); alloc = 0;
            for(int i = 1;i <= n;i++) a[i] = read();
            for(int i = 1;i < n;i++)
            {
                int u = read(),v = read();
                adde(u,v);
            }
            s1 = read(),s2 = read(),p1 = read(),p2 = read();
            mid = 1000000000;
            clr(f);
            dp(1,0);
            ans = 0;
            for(int i = 0;i <= s1;i++)
                for(int j = 0;j <= s2;j++)
                    ans = max(ans,f[1][i][j]);        
            printf("%lld ",ans);
            int l = 0,r = 1000000000,prel = 0,prer = 0;
            int res = 0;
            while(l < r)
            {
                mid = (l + r) >> 1ll;
                if(solve()) r = mid,res = mid;
                else l = mid + 1;
                if(l == prel && r == prer) res = r,r--;
                prel = l,prer = r;
            }
            printf("%lld
    ",res);
        }
    }
    /*
    1
    4
    5 30 20 20
    1 2
    1 3
    3 4
    4 1 10 15
    */
                
    View Code
  • 相关阅读:
    C# 删除指定目录下的所有文件及文件夹
    C# 数组集合分页 Skip Take
    MongoDB模糊查询 工具
    C# skip 重试执行代码段
    C# 加载配置文件
    消息队列MSMQ的使用
    C#中const和readonly的区别
    JSP页面中的tab页
    使用jquery获取单选按钮radio的值
    JSP页面获取下来框select选中项的值和文本的方法
  • 原文地址:https://www.cnblogs.com/LM-LBG/p/11329376.html
Copyright © 2011-2022 走看看