zoukankan      html  css  js  c++  java
  • [hdu7078]Pty with card

    显然问题被分为两部分,先考虑如何求$F(n)$——

    令第一次所选的人编号为1,其之后所有人按顺时针依次编号为$2,3,...,n$,那么用一个序列来描述状态,其中第$i$个元素为当前存在的人中编号第$i$小的人手牌数(显然序列长度即为剩余人数)

    初始序列显然为${1,1,...,1}$(共$n$个1),并对$n$的奇偶性分类讨论:

    1.若$n$为奇数,则$n$轮后序列为${3,2,2,...,2}$(其中共$frac{n-3}{2}$个2)

    2.若$n$为偶数,则$n$轮后序列为${4,2,2,...,2}$(其中共$frac{n}{2}-2$个2)

    (关于这个结果,手动模拟若干次即可得到规律)

    注意到此时所有元素都$ge 2$,那么若序列长度为$2m+1$(其中$min Z^{+}$),循环节即恰为$4m+2$

    关于这个性质,考虑两轮中每一个人都会在奇数轮操作一次、偶数轮操作一次,那么总共即恰好失去3张卡片并得到3张卡片,因此卡牌数量不变,且由于初始有两张卡片,不会有人"出局"

    下面,考虑序列长度为$2m$,再对两类分别讨论:

    1.若$n$为奇数(注意不是$m$),则$2m$轮后序列为${2,3,1,3,1,3...,1,3}$(其中共$m-1$对$1,3$),再$2m$轮后序列为${5,4,4,...,4}$(其中共$m-1$个4)

    不难发现如果序列长度仍是偶数,其又会变为${9,8,8,...,8},{17,16,16,...,16},...$(可以归纳证明),直至序列长度为奇数(答案为序列长度的两倍)

    2.若$n$为偶数,类似的$4m$轮后序列为${6,4,4,...,4}$(其中共$m-1$个4),如果序列长度仍是偶数,其又会变为${10,8,8,...,8},{18,16,16,...,16},...$,直至序列长度为奇数

    (另外,若最终序列长度为1则$F(n)=0$)

    综上,有
    $$
    F(n)=egin{cases}0&left(nle 2 ight)or left(lowbit(m)=1 ight)\frac{2m}{lowbit(m)}&left(nge 3 ight)and left(lowbit(m) e 1 ight)end{cases}
    $$
    (其中$m=lfloorfrac{n-1}{2} floor$,$lowbit(m)$指$m$二进制下最低位上的1对应的值)

    接下来,考虑如何求$forall 1le xle n,sum_{i=1}^{n}F(v_{i}+d(i,x))$——

    将其点分治,问题即是要维护一个集合$S$,支持:1.加入一个元素$x$;2.(给定$x$)查询$sum_{yin S}F(x+y)$

    这个并不容易维护,但注意到查询中$x$即为某点到当前点分中心的距离,是连续变化的,因此这个问题还可以看作支持:1.加入一个元素$x$;2.令所有元素+1;3.查询$sum_{xin S}F(x)$

    维护一棵trie树,并且从低到高存储数字,依次考虑这些操作:

    1.加入一个元素$x$,与普通的trie树相同

    2.令所有元素+1,即不断交换左右儿子,并递归(新的)左儿子即可

    3.查询$sum_{xin S}F(x)$,不断递归左儿子,维护子树中所有元素的和即可(注意去掉$lowbit(m)=1$的情况)

    由此,单次操作时间复杂度为$o(log n)$,总复杂度即$o(nlog^{2}n)$,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 100005
      4 #define ll long long
      5 struct Edge{
      6     int nex,to;
      7 }edge[N<<1];
      8 vector<int>v[N];
      9 int E,rt,t,n,x,y,mx,a[N],head[N],vis[N],sz[N],f[N<<2];
     10 ll ans[N];
     11 int lowbit(int k){
     12     return (k&(-k));
     13 }
     14 namespace Trie{
     15     int V,tag,st[N],L[N*6],sz[N*6],ch[N*6][2];
     16     ll sum[N*6];
     17     int New(){
     18         int k=++V;
     19         L[k]=sz[k]=sum[k]=ch[k][0]=ch[k][1]=0;
     20         return k;
     21     }
     22     ll get(int k){
     23         return sum[k]+(ll)tag*sz[k];
     24     }
     25     void init(){
     26         V=tag=0;
     27         New();
     28     }
     29     void add_val(int x){
     30         st[0]=st[1]=1;
     31         for(int i=0,k=1;i<18;i++){
     32             int p=((x>>i)&1);
     33             if (!ch[k][p])ch[k][p]=New();
     34             k=st[++st[0]]=ch[k][p];
     35         }
     36         for(int i=1;i<=st[0];i++)sz[st[i]]++,sum[st[i]]+=x;
     37         L[st[st[0]]]=st[st[0]];
     38         for(int i=st[0]-1;i;i--)L[st[i]]=L[ch[st[i]][0]];
     39     }
     40     void Add(){
     41         tag++;
     42         st[0]=st[1]=1;
     43         for(int i=0,k=1;(i<18)&&(k);i++){
     44             swap(ch[k][0],ch[k][1]);
     45             k=st[++st[0]]=ch[k][0];
     46         }
     47         L[st[st[0]]]=st[st[0]];
     48         for(int i=st[0]-1;i;i--)L[st[i]]=L[ch[st[i]][0]];
     49     }
     50     ll query(){
     51         ll ans=0;
     52         for(int i=1,k=ch[1][0];(i<18)&&(k);i++){
     53             ans+=(get(ch[k][1])-get(L[ch[k][1]])>>i-1);
     54             k=ch[k][0];
     55         }
     56         tag--;
     57         for(int i=1,k=ch[1][1];(i<18)&&(k);i++){
     58             ans+=(get(ch[k][1])-get(L[ch[k][1]])>>i-1);
     59             k=ch[k][0];
     60         }
     61         tag++;
     62         return ans;
     63     }
     64 }
     65 void add_edge(int x,int y){
     66     edge[E].nex=head[x];
     67     edge[E].to=y;
     68     head[x]=E++;
     69 }
     70 void get_sz(int k,int fa){
     71     sz[k]=1;
     72     for(int i=head[k];i!=-1;i=edge[i].nex)
     73         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
     74             get_sz(edge[i].to,k);
     75             sz[k]+=sz[edge[i].to];
     76         }
     77 }
     78 void get_rt(int k,int fa,int s){
     79     int mx=s-sz[k];
     80     for(int i=head[k];i!=-1;i=edge[i].nex)
     81         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
     82             get_rt(edge[i].to,k,s);
     83             mx=max(mx,sz[edge[i].to]);
     84         }
     85     if (mx<=(s>>1))rt=k;
     86 }
     87 void get_val(int k,int fa,int s){
     88     if (mx<s)v[++mx].clear();
     89     v[s].push_back(k);
     90     Trie::add_val(a[k]+s);
     91     for(int i=head[k];i!=-1;i=edge[i].nex)
     92         if ((!vis[edge[i].to])&&(edge[i].to!=fa))get_val(edge[i].to,k,s+1);
     93 }
     94 void calc(int k,int p){
     95     Trie::init();
     96     mx=0,v[0].clear();
     97     get_val(k,0,p);
     98     p=1-(p<<1);
     99     for(int i=0;i<=mx;i++){
    100         ll s=Trie::query();
    101         for(int j=0;j<v[i].size();j++)ans[v[i][j]]+=p*s;
    102         Trie::Add();
    103     }
    104 }
    105 void dfs(int k){
    106     get_sz(k,0);
    107     get_rt(k,0,sz[k]);
    108     calc(rt,0);
    109     vis[rt]=1;
    110     for(int i=head[rt];i!=-1;i=edge[i].nex)
    111         if (!vis[edge[i].to])calc(edge[i].to,1);
    112     for(int i=head[rt];i!=-1;i=edge[i].nex)
    113         if (!vis[edge[i].to])dfs(edge[i].to);
    114 }
    115 int main(){
    116     for(int i=2;i<(N<<2);i++)
    117         if (lowbit(i>>1)==1)f[i]=0;
    118         else f[i]=((i>>1)/lowbit(i>>1)<<1);
    119     scanf("%d",&t);
    120     while (t--){
    121         scanf("%d",&n);
    122         E=0;
    123         memset(head,-1,sizeof(head));
    124         memset(vis,0,sizeof(vis));
    125         memset(ans,0,sizeof(ans));
    126         for(int i=1;i<=n;i++){
    127             scanf("%d",&a[i]);
    128             a[i]--;
    129         }
    130         for(int i=1;i<n;i++){
    131             scanf("%d%d",&x,&y);
    132             add_edge(x,y);
    133             add_edge(y,x);
    134         }
    135         dfs(1);
    136         for(int i=1;i<n;i++)printf("%lld ",ans[i]);
    137         printf("%lld
    ",ans[n]);
    138     }
    139     return 0;
    140 } 
    View Code
  • 相关阅读:
    看动画学算法之:排序-归并排序
    看动画学算法之:排序-选择排序
    【电脑】第3期:电脑如何打开上帝模式?
    限时删除!能挑战idm的下片神器,最快33M/S
    基本类型计算中浮点数的错误
    字符数组的toString方法打印的是地址值
    boolean类型的成员变量自动生成get方法的问题
    多态的使用
    抽象类和接口的使用关系
    接口的注意事项
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15180596.html
Copyright © 2011-2022 走看看