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

    A.Duff and Weight Lifting(思维)

    显然题目中只有一种情况可以合并 2^a+2^a=2^(a+1)。
    我们把给出的mi排序一下,模拟合并操作即可。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # 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
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    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');
    }
    const int N=1000005;
    //Code begin...
    
    int a[N];
    
    int main ()
    {
        int n;
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i);
        sort(a+1,a+n+1);
        int now=a[1], cnt=1, ans=0;
        FOR(i,2,n) {
            if (now==a[i]) cnt++;
            else {
                while (now!=a[i]&&cnt>1) {
                    ++now;
                    ans+=(cnt&1);
                    cnt/=2;
                }
                if (now==a[i]) cnt++;
                else ans+=cnt, cnt=1, now=a[i];
            }
        }
        while (cnt) ans+=(cnt&1), cnt/=2;
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    B.Duff in Beach(DP)

    这是一个计数问题。考虑DP。
    考虑L<=n*k.
    由于n*k<=1e6.我们把a数组变成b数组。令dp[i]表示以b[i]结尾的方法数。
    那么dp[i]=sigma(上一段的数小于b[i]的dp[i])。
    sigma我们可以用类似前缀和的办法维护一下。

    考虑L>n*k.
    此时数组太大不好直接构造,我们考虑把n*k的元素的最后n个数字平移到n*k后面的数字。
    发现方法数是一样的。我们再统计每个数字可以平移多少次就OK了。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # 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
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    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');
    }
    const int N=1000005;
    //Code begin...
    
    int to[N];
    LL dp[N], sum[N];
    PII a[N];
    
    int comp(const void * a, const void * b){return *(int *)a-*(int *)b;}
    int main ()
    {
        int n, k, cnt=0;
        LL l, ans=0;
        scanf("%d%lld%d",&n,&l,&k);
        FO(i,0,n) a[i].first=Scan(), a[i].second=i;
        sort(a,a+n);
        to[a[0].second]=++cnt;
        FO(i,1,n) {
            if (a[i].first==a[i-1].first) to[a[i].second]=cnt;
            else to[a[i].second]=++cnt;
        }
        int m=(l%n?l%n:n);
        FO(i,0,min((LL)n*k,l)) {
            if (i && i%n==0) {
                FOR(j,1,cnt) sum[j]=0;
                FO(j,i-n,i) sum[to[j%n]]=(sum[to[j%n]]+dp[j])%MOD;
                FOR(j,1,cnt) sum[j]=(sum[j-1]+sum[j])%MOD;
             }
            if (i<n) dp[i]=1;
            else dp[i]=(1+sum[to[i%n]])%MOD;
            ans=(ans+dp[i])%MOD;
            if (l>n*k && i>=n*k-n) ans=(ans+((l-i-1)/n%MOD)*dp[i]%MOD)%MOD;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    C.Duff in the Army(LCA)

    题目要求维护树的路径上的标号最小的a个数。(a<=10)

    维护路径上的某些东西一般有LCT,LCA,树形DP,树链刨分,树分治。
    由于题目允许离线,于是我们可以类似LCA预处理出一坨东西。
    fa[x][i][]里面的是x节点到x节点的2^i个父亲中的标号最小的10个数。
    合并的时候归并一下,最后求答案的时候就类似求LCA一样边爬边归并。
    细节很多。
    复杂度O((n+q)*logn).

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # 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
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    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');
    }
    const int N=100005;
    //Code begin...
    
    struct Edge{int p, next;}edge[N<<1];
    int head[N], cnt=1;
    int bin[20], fa[N][20][12], dep[N], temp[12], ans[12];
    VI node[N];
    
    void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}
    void bin_init(){bin[0]=1; FO(i,1,20) bin[i]=bin[i-1]<<1;}
    void merge(int x, int nn)
    {
        int y=fa[x][nn-1][0], i=1, j=1, k=1;
        while (k<=10) {
            if (fa[x][nn-1][i]==0 && fa[y][nn-1][j]==0) break;
            if (fa[x][nn-1][i]==0) fa[x][nn][k++]=fa[y][nn-1][j++];
            else if (fa[y][nn-1][j]==0) fa[x][nn][k++]=fa[x][nn-1][i++];
            else {
                fa[x][nn][k++]=min(fa[x][nn-1][i], fa[y][nn-1][j]);
                if (fa[x][nn-1][i]<fa[y][nn-1][j]) ++i;
                else ++j;
            }
        }
    }
    void merge_(int x, int nn)
    {
        int i=1, j=1, k=1;
        mem(temp,0);
        FOR(l,1,10) temp[l]=ans[l];
        mem(ans,0);
        while (k<=10) {
            if (fa[x][nn][i]==0&&temp[j]==0) break;
            if (fa[x][nn][i]==0) ans[k++]=temp[j++];
            else if (temp[j]==0) ans[k++]=fa[x][nn][i++];
            else {
                ans[k++]=min(fa[x][nn][i],temp[j]);
                if (fa[x][nn][i]<temp[j]) ++i;
                else if (fa[x][nn][i]>temp[j]) ++j;
                else ++i, ++j;
            }
        }
    }
    void dfs(int x, int fat)
    {
        fa[x][0][0]=fat;
        if (node[fat].size()) for (int i=0; i<min((int)node[fat].size(),10); ++i) fa[x][0][i+1]=node[fat][i];
        for (int i=1; bin[i]<=dep[x]; ++i) fa[x][i][0]=fa[fa[x][i-1][0]][i-1][0], merge(x,i);
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            if (v==fat) continue;
            dep[v]=dep[x]+1;
            dfs(v,x);
        }
    }
    void sol(int x, int y)
    {
        int l=0, j=0, k=1;
        while (k<=10) {
            if (l>=node[x].size()&&j>=node[y].size()) break;
            if (l>=node[x].size()) ans[k++]=node[y][j], ++j;
            else if (j>=node[y].size()) ans[k++]=node[x][l], ++l;
            else {
                ans[k++]=min(node[x][l],node[y][j]);
                if (node[x][l]<node[y][j]) ++l;
                else if (node[x][l]>node[y][j]) ++j;
                else ++l, ++j;
            }
        }
        if (dep[x]<dep[y]) swap(x,y);
        int t=dep[x]-dep[y];
        for (int i=0; bin[i]<=t; ++i) if (bin[i]&t) merge_(x,i), x=fa[x][i][0];
        for (int i=19; i>=0; --i) if (fa[x][i][0]!=fa[y][i][0]) merge_(x,i), merge_(y,i), x=fa[x][i][0], y=fa[y][i][0];
        if (x==y) return ;
        else {merge_(x,0); return ;}
    }
    int main ()
    {
        bin_init();
        int n, m, q, u, v, a;
        scanf("%d%d%d",&n,&m,&q);
        FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u);
        FOR(i,1,m) scanf("%d",&u), node[u].pb(i);
        FOR(i,1,n) sort(node[i].begin(),node[i].end());
        dfs(1,0);
        while (q--) {
            scanf("%d%d%d",&u,&v,&a);
            mem(ans,0);
            sol(u,v);
            int mark;
            for (mark=1; mark<=11&&ans[mark]; ++mark) ;
            mark=min(mark-1,a);
            printf("%d",mark);
            FOR(i,1,mark) printf(" %d",ans[i]);
            putchar('
    ');
        }
        return 0;
    }
    View Code

    D.Duff in Mafia(待填坑)

    E.Duff as a Queen(线段树+线性基)

    给出一个数列(n<=2e5),有两种操作(q<=2e5)
    1.给定区间[l,r]内的数都异或k。
    2.询问区间[l,r]能够相互异或出几种数。

    对于第2种操作,显然可以对区间[l,r]搞出线性基,答案就是1<<(线性基的个数).
    注意到一个性质。
    对于a1 a2 a3 ... an. 这些数的线性基等于 a1 a1^a2 a2^a3 ... an-1^an.的线性基。
    大概就是由于这两个数列能够互相异或出来,于是能异或出来的数字种数都是相等的。

    于是第一个操作就是 al^k al+1^k al+2^k ... ar^k.
    对于线性基就是 al-1^a1^k a1^al+1 al+1^al+2 ... ar-1^ar ar^ar+1^k.

    于是我们需要维护两个数列 一个原数列, 一个线性基与原数列相同的数列(次数列)
    用BIT或者线段树维护原数列。
    用线段树维护次数列的线性基。

    答案即为所求。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # 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
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    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');
    }
    const int N=200005;
    //Code begin...
    
    int a[N], seg[N<<2][32], tree[N], n, q, ans[32];
    
    void add(int x, int val){while (x<=n) tree[x]^=val, x+=lowbit(x);}
    int sum(int x){int ans=0; while (x) ans^=tree[x], x-=lowbit(x); return ans;}
    void push_up(int p)
    {
        mem(seg[p],0);
        FOR(c,0,30) seg[p][c]=seg[p<<1][c];
        for (int c=30; c>=0; --c) {
            int x=seg[p<<1|1][c];
            for (int i=c; i>=0; --i) {
                if (!(x>>i)) continue;
                if (!seg[p][i]) {seg[p][i]=x; break;}
                x^=seg[p][i];
            }
        }
    }
    void bulid(int p, int l, int r)
    {
        if (l==r) {
            for (int c=30; c>=0; --c) if (a[l]>>c) {seg[p][c]=a[l]; break;}
            return ;
        }
        int mid=(l+r)>>1;
        bulid(lch); bulid(rch); push_up(p);
    }
    void update(int p, int l, int r, int L, int K)
    {
        if (L<l || L>r) return ;
        if (L==l && L==r) {
            a[L]^=K;
            mem(seg[p],0);
            for (int c=30; c>=0; --c) if (a[L]>>c) {seg[p][c]=a[L]; break;}
        }
        else {
            int mid=(l+r)>>1;
            update(lch,L,K); update(rch,L,K); push_up(p);
        }
    }
    void query(int p, int l, int r, int L, int R)
    {
        if (R<l || L>r) return ;
        if (L<=l && R>=r) {
            for (int i=30; i>=0; --i) {
                int x=seg[p][i];
                for (int c=i; c>=0; --c) {
                    if (!(x>>c)) continue;
                    if (!ans[c]) {ans[c]=x; break;}
                    x^=ans[c];
                }
            }
        }
        else {
            int mid=(l+r)>>1;
            query(lch,L,R), query(rch,L,R);
        }
    }
    int main ()
    {
        int flag, l, r, k;
        scanf("%d%d",&n,&q);
        FOR(i,1,n) scanf("%d",a+i);
        for (int i=n; i>=1; --i) a[i]^=a[i-1], add(i,a[i]);
        bulid(1,1,n);
        while (q--) {
            scanf("%d%d%d",&flag,&l,&r);
            if (flag==1) {
                scanf("%d",&k);
                update(1,1,n,l,k); add(l,k);
                if (r!=n) update(1,1,n,r+1,k), add(r+1,k);
            }
            else {
                mem(ans,0);
                if (l!=r) query(1,1,n,l+1,r);
                int temp=sum(l);
                for (int i=30; i>=0; --i) {
                    if (!(temp>>i)) continue;
                    if (!ans[i]) {ans[i]=temp; break;}
                    temp^=ans[i];
                }
                int cnt=0;
                FOR(i,0,30) if (ans[i]) ++cnt;
                printf("%d
    ",1<<cnt);
            }
        }
        return 0;
    }
    View Code

    F.Duff is Mad(待填坑)

  • 相关阅读:
    百度Hi之CSRF蠕虫攻击
    Portlet之讲解
    try-catch语句讲解
    unset之讲解
    MySQL bin-log 日志清理方式
    php数组array_push()和array_pop()以及array_shift()函数
    php中的func_num_args、func_get_arg与func_get_args函数
    PHP is_callable 方法
    如何实现php异步处理
    Mysql并发时经典常见的死锁原因及解决方法
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6383607.html
Copyright © 2011-2022 走看看