zoukankan      html  css  js  c++  java
  • 【20151105noip膜你赛】bzoj3652 bzoj3653

    题目仿佛在讽刺我。。。

    第一题:

    题解:

    考虑枚举区间右端点,维护所以左到当前的 and 和 or 。注意 and 每次变化至少有一个二进制位从1变 0,or 每次至少有一个位从0变 1,所以最多有log段不同的值。用两个链表维护这log个值,暴力计算答案即可。
    O( nlogn)

    我原本打的是一个树状数组的O(nlognlogn)算法。。然后被卡了。。只有50分。。

    看了看奥爷爷的代码,发现他直接用一个链表同时维护and和or值,真奇怪啊不是(logn)^2吗。。然后男神说这个也是log级别的,因为两个区间不同只能是边界上跨越。

    代码:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 
     8 typedef long long LL;
     9 const int N=100010;
    10 const LL mod=1000000007;
    11 int n,al;
    12 struct node{int last,next;LL t0,t1,sum;}a[N];
    13 
    14 int main()
    15 {
    16     // freopen("a.in","r",stdin);
    17     // freopen("a.out","w",stdout);
    18     freopen("value.in","r",stdin);
    19     freopen("value.out","w",stdout);
    20     scanf("%d",&n);
    21     al=0;
    22     int x,last=0;
    23     LL ans=0;
    24     for(int i=1;i<=n;i++)
    25     {
    26         scanf("%d",&x);
    27         for(int j=last;j;j=a[j].last)
    28         {
    29             a[j].t0&=x;
    30             a[j].t1|=x;    
    31         }
    32         a[++al].t0=x;a[al].t1=x;a[al].sum=1;
    33         a[al].last=last;
    34         if(last) a[last].next=al;
    35         last=al;
    36 
    37         for(int j=last;j;j=a[j].last)
    38         {
    39             int p=a[j].last;
    40             if(p && a[p].t0==a[j].t0 && a[p].t1==a[j].t1)
    41             {
    42                 a[p].sum+=a[j].sum;
    43                 a[p].next=a[j].next;
    44                 if(a[j].next) a[a[j].next].last=p;
    45                 else last=p;//debug last=p not last=j
    46             }
    47         }
    48         
    49         for(int j=last;j;j=a[j].last)
    50         {
    51             ans=(ans+((((a[j].t0*a[j].t1)%mod)*a[j].sum)%mod))%mod;
    52         }
    53     }
    54     printf("%I64d
    ",ans);
    55     return 0;
    56 }

    第二题 bzoj3652

    3652: 大新闻

    Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge
    Submit: 207  Solved: 106
    [Submit][Status][Discuss]

    Description

    Input 两个整数n和p。p/100表示题目中描述的概率

    Output 输出期望在模1000000007下的值


    Sample Input

    3 50

    Sample Output

    2

     

    HINT

     


    1<=N<=10^18

     
    题解:
    这题的数位dp达到我都昏了。。因为我打得挺复杂的。。
    首先贴一个我的代码吧。
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 typedef long long LL;
      9 const LL mod=1000000007;
     10 const int N=100;
     11 LL n,m,p,bit[N],vis[N][2][2],cnt[N][2],f[N][2][2][2][2],g[N][2][2];
     12 int d[N];
     13 
     14 LL ad(LL x,LL y){return ((x+y)%mod+mod)%mod;}
     15 
     16 int find_vis(int x,int now,int flag)
     17 {
     18     if(x==0) return 1;
     19     if(vis[x][now][flag]!=-1) return vis[x][now][flag];
     20     int mx=1;if(flag || (x-1==0)) mx=d[x-1];
     21     LL ans=0;
     22     for(int i=0;i<=mx;i++)
     23     {
     24         ans=ad(ans,find_vis(x-1,i,flag&(i==d[x-1])));
     25     }
     26     vis[x][now][flag]=ans;
     27     // printf("x = %d  now = %d  flag = %d  = %d
    ",x,now,flag,ans); 
     28     return ans;
     29 }
     30 
     31 void find_cnt()
     32 {
     33     for(int i=1;i<=m;i++) cnt[i][0]=cnt[i][1]=bit[m];
     34     for(int i=m;i>=1;i--)
     35     {
     36         if(d[i]==0) 
     37         {
     38             for(int j=i-1;j>=1;j--) 
     39             {
     40                 cnt[j][0]=ad(cnt[j][0],-bit[i-1]);
     41                 cnt[j][1]=ad(cnt[j][1],-bit[i-1]);
     42             }
     43             cnt[i][1]=ad(cnt[i][1],-bit[i]);
     44             for(int j=i+1;j<=m;j++)
     45             {
     46                 cnt[j][d[j]]=ad(cnt[j][d[j]],-bit[i]);
     47             }
     48         }
     49     }
     50     
     51 }
     52 
     53 int dfs(int x,int now1,int now2,int flag1,int flag2) 
     54 {
     55     if(x==0) return 0;
     56     
     57     if(f[x][now1][now2][flag1][flag2]!=-1) return f[x][now1][now2][flag1][flag2];
     58     LL ans=0,now=0;
     59     int mx1=1;if(flag1 || (x-1==0)) mx1=d[x-1];
     60     int mx2=1;if(flag2 || (x-1==0)) mx2=d[x-1];
     61     if(now1+now2==1) ans=ad(ans,(vis[x][now1][flag1]*bit[x])%mod);
     62     for(int i=0;i<=mx1;i++)
     63     {
     64         if(flag2 && (i^1)>mx2) 
     65         {
     66             int f1=flag1&(i==d[x-1]);
     67             int f2=flag2&(0==d[x-1]);
     68             ans=ad(ans,dfs(x-1,i,0,f1,f2));
     69         }
     70         else 
     71         {
     72             int f1=flag1&(i==d[x-1]);
     73             int f2=flag2&((i^1)==d[x-1]);
     74             ans=ad(ans,dfs(x-1,i,i^1,f1,f2));
     75         }
     76     }
     77     f[x][now1][now2][flag1][flag2]=ans;
     78     // printf("f x = %d  now1 = %d  now2 = %d  flag1 = %d  flag2 = %d  ans = %d
    ",x,now1,now2,flag1,flag2,ans); 
     79     return ans;
     80 }
     81 
     82 int DFS(int x,int now,int flag)
     83 {
     84     if(x==0) return 0;
     85     if(g[x][now][flag]!=-1) return g[x][now][flag]; 
     86     int mx=1;if(flag || (x-1==0)) mx=d[x-1];
     87     LL ans=0;
     88     ans=ad(ans,(((vis[x][now][flag]*cnt[x][now^1])%mod)*bit[x])%mod);
     89     for(int i=0;i<=mx;i++)
     90     {
     91         ans=ad(ans,DFS(x-1,i,flag&(i==d[x-1])));
     92     }
     93     g[x][now][flag]=ans;
     94     // printf("g x = %d  now = %d  flag = %d  = %d
    ",x,now,flag,ans); 
     95     return ans;
     96 }
     97 
     98 LL quickpow(LL x,LL y)
     99 {
    100     LL ans=1;
    101     while(y) 
    102     {
    103         if(y&1) ans=(ans*x)%mod;
    104         x=(x*x)%mod;
    105         y/=2;
    106     }
    107     return ans;
    108 }
    109 
    110 int main()
    111 {
    112     freopen("a.in","r",stdin);
    113     // freopen("a.out","w",stdout);
    114     // freopen("news.in","r",stdin);
    115     // freopen("news.out","w",stdout);
    116     scanf("%lld%lld",&n,&p);
    117     LL x=n-1;m=0;
    118     memset(d,0,sizeof(d));
    119     while(x)
    120     {
    121         d[++m]=x%2;
    122         x/=2;
    123     }
    124     bit[1]=1;
    125     for(int i=2;i<=70;i++) bit[i]=(bit[i-1]*2)%mod;
    126     memset(cnt,0,sizeof(cnt));
    127     memset(vis,-1,sizeof(vis));
    128     memset(f,-1,sizeof(f));
    129     memset(g,-1,sizeof(g));
    130     find_vis(m+1,0,1);
    131     find_cnt();
    132     
    133     LL a1=dfs(m+1,0,0,1,1);
    134     LL a2=DFS(m+1,0,1);
    135     LL bn=quickpow(n%mod,mod-2);
    136     LL bb=quickpow(100,mod-2);
    137     LL ans=0;
    138     
    139     // for(int i=1;i<=3;i++)
    140         // for(int j=0;j<=1;j++)
    141             // printf("cnt %d %d = %I64d
    ",i,j,cnt[i][j]);
    142         
    143     ans=ad(ans,(((a1*bn)%mod)*((p*bb)%mod))%mod);
    144     ans=ad(ans,(((((a2*bn)%mod)*bn)%mod)*(((100-p)*bb)%mod))%mod);
    145     // printf("a1=%I64d a2=%I64d
    ",a1,a2);
    146     printf("%lld
    ",ans);
    147     return 0;
    148 }
    View Code

    x表示当前填到哪一位。flag表示当前是否和边界重合。

    dfs是做加密的情况,也就是确定当前填的x,然后让跟它异或的y尽量大。

    DFS是做不加密的情况,也就是确定当前填的x,然后y所有可能都算上。

    其中vis是维护到当前状态的方案数。

    cnt是表示当前某个数位上是0或1的方案数。

    好了还是这种做法太复杂了。。

    学习了一下出题人的做法。

    出题人题解:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 
      9 typedef long long LL;
     10 const LL mod=1000000007;
     11 const int N=110;
     12 LL n,m,p,bit[N],f[N][2][2],g[N][2][2];
     13 int a[N];
     14 
     15 LL quickpow(LL x,LL y)
     16 {
     17     LL ans=1;
     18     while(y)
     19     {
     20         if(y&1) ans=(ans*x)%mod;
     21         x=(x*x)%mod;
     22         y/=2;
     23     }
     24     return ans;
     25 }
     26 
     27 void dp_1()
     28 {
     29     memset(f,0,sizeof(f));
     30     memset(g,0,sizeof(g));
     31     g[0][1][1]=1;
     32     int now1,now2;
     33     for(int i=0;i<m;i++)
     34         for(int x1=0;x1<=1;x1++)
     35             for(int x2=0;x2<=1;x2++)
     36             {
     37                 if(g[i][x1][x2]==0) continue;
     38                 for(int j=0;j<=1;j++)
     39                 {
     40                     int k=j^1;
     41                     if(j>a[i+1] && x1) continue;
     42                     if(j==a[i+1] && x1) now1=1;
     43                     else now1=0;
     44                     if(k>a[i+1] && x2) k=0;
     45                     if(k==a[i+1] && x2) now2=1;
     46                     else now2=0;
     47                     g[i+1][now1][now2]=(g[i+1][now1][now2]+g[i][x1][x2])%mod;
     48                     f[i+1][now1][now2]=(f[i+1][now1][now2]+f[i][x1][x2]+((g[i][x1][x2]*(j^k))%mod*bit[i+1])%mod)%mod;
     49                 }
     50             }
     51 }
     52 
     53 
     54 void dp_2()
     55 {
     56     memset(f,0,sizeof(f));
     57     memset(g,0,sizeof(g));
     58     g[0][1][1]=1;
     59     int now1,now2;
     60     for(int i=0;i<m;i++)
     61         for(int x1=0;x1<=1;x1++)
     62             for(int x2=0;x2<=1;x2++)
     63             {
     64                 if(g[i][x1][x2]==0) continue;
     65                 for(int j=0;j<=1;j++)
     66                 {
     67                     if(j>a[i+1] && x1) continue;
     68                     if(x1 && j==a[i+1]) now1=1;
     69                     else now1=0;
     70                     for(int k=0;k<=1;k++)
     71                     {
     72                         if(k>a[i+1] && x2) continue;
     73                         if(x2 && k==a[i+1]) now2=1;
     74                         else now2=0;
     75                         g[i+1][now1][now2]=(g[i+1][now1][now2]+g[i][x1][x2])%mod;
     76                         f[i+1][now1][now2]=(f[i+1][now1][now2]+f[i][x1][x2]+(g[i][x1][x2]*(j^k))%mod*bit[i+1]%mod)%mod;
     77                     }
     78                 }
     79             }
     80 }
     81 
     82 
     83 int main()
     84 {
     85     freopen("a.in","r",stdin);
     86     // freopen("news.in","r",stdin);
     87     // freopen("news.out","w",stdout);
     88     scanf("%lld%lld",&n,&p);
     89     LL x=n-1,a1=0,a2=0;m=0;
     90     while(x)
     91     {
     92         a[++m]=x%2;
     93         x/=2;
     94     }
     95     for(int i=1;i<=m/2;i++) swap(a[i],a[m-i+1]);
     96     bit[m]=1;
     97     for(int i=m-1;i>=1;i--) bit[i]=(bit[i+1]*2)%mod;
     98     // for(int i=1;i<=m;i++) printf("%d ",a[i]);printf("
    ");
     99     
    100     dp_1();
    101     for(int i=0;i<=1;i++)
    102         for(int j=0;j<=1;j++)
    103             a1=(a1+f[m][i][j])%mod;
    104     dp_2();
    105     for(int i=0;i<=1;i++)
    106         for(int j=0;j<=1;j++)
    107             a2=(a2+f[m][i][j])%mod;
    108     
    109     LL bn=quickpow(n%mod,mod-2);
    110     LL bb=quickpow(100,mod-2);
    111     LL ans=0;
    112     
    113     ans=(ans+((a1*bn%mod)*(p*bb%mod))%mod)%mod;
    114     ans=(ans+((((a2*bn%mod)*bn)%mod)*((100-p)*bb%mod))%mod)%mod;
    115     // printf("a1=%I64d a2=%I64d
    ",a1,a2);
    116     printf("%lld
    ",ans);
    117     
    118     return 0;
    119 }

    第三题:

    3653: 谈笑风生

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 689  Solved: 264
    [Submit][Status][Discuss]

    Description

    设T 为一棵有根树,我们做如下的定义:
    • 设a和b为T 中的两个不同节点。如果a是b的祖先,那么称“a比b不知道
    高明到哪里去了”。
    • 设a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定
    常数x,那么称“a 与b 谈笑风生”。
    给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点。你需
    要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足:
    1. a、b和 c为 T 中三个不同的点,且 a为p 号节点;
    2. a和b 都比 c不知道高明到哪里去了;
    3. a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。

    Input

    输入文件的第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。
    接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。

     

     

    Output

    输出 q 行,每行对应一个询问,代表询问的答案。

     

    Sample Input

    5 3
    1 2
    1 3
    2 4
    4 5
    2 2
    4 1
    2 3

    Sample Output


    3
    1
    3

    HINT

     

     


    1<=P<=N

    1<=K<=N

    N<=300000

    Q<=300000

     
    题解:
     
    跟我最近做的主席树模版题非常像啊。。
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 typedef long long LL;
      9 const int N=2*100000,M=30*100000;
     10 // const int N=2*300000,M=30*300000;
     11 struct node{
     12     int x,y,next;
     13 }a[N];
     14 struct trnode{
     15     int lc,rc;
     16     LL sum;
     17 }t[M];
     18 int n,m,num,len,tl;
     19 int first[N],dfn[N],edfn[N],dep[N],tot[N],root[N];
     20 
     21 int minn(int x,int y){return x<y ? x:y;}
     22 
     23 void ins(int x,int y)
     24 {
     25     a[++len].x=x;a[len].y=y;
     26     a[len].next=first[x];first[x]=len;
     27 }
     28 
     29 int add(int rt,int x,int d)
     30 {
     31     int now=++tl,tmp=now;
     32     int l=1,r=n,mid;
     33     while(l<r)
     34     {
     35         mid=(l+r)/2;
     36         if(x<=mid)
     37         {
     38             r=mid;
     39             t[now].lc=++tl;
     40             t[tl].lc=t[tl].rc=0;
     41             t[now].rc=t[rt].rc;
     42             rt=t[rt].lc;
     43             now=tl;
     44         }
     45         else 
     46         {
     47             l=mid+1;
     48             t[now].lc=t[rt].lc;
     49             t[now].rc=++tl;
     50             t[tl].lc=t[tl].rc=0;
     51             rt=t[rt].rc;
     52             now=tl;
     53         }
     54         t[now].sum=t[rt].sum+d;
     55     }
     56     return tmp;
     57 }
     58 
     59 LL query(int lx,int rx,int ql,int qr,int l,int r)
     60 {
     61     if(ql==l && qr==r) return t[rx].sum-t[lx].sum;//debug 一开始更新到了叶子节点。。
     62     int mid=(l+r)/2;
     63     if(qr<=mid) return query(t[lx].lc,t[rx].lc,ql,qr,l,mid);
     64     if(ql>mid) return query(t[lx].rc,t[rx].rc,ql,qr,mid+1,r);
     65     return query(t[lx].lc,t[rx].lc,ql,mid,l,mid)+query(t[lx].rc,t[rx].rc,mid+1,qr,mid+1,r);
     66 }
     67 
     68 void dfs(int x,int fa)
     69 {
     70     dep[x]=dep[fa]+1;
     71     dfn[x]=++num;
     72     tot[x]=1;
     73     for(int i=first[x];i;i=a[i].next)
     74     {
     75         int y=a[i].y;
     76         if(y==fa) continue;
     77         dfs(y,x);
     78         tot[x]+=tot[y];
     79     }
     80     edfn[x]=num;
     81 }
     82 
     83 void build_tree(int x,int fa)
     84 {
     85     root[dfn[x]]=add(root[dfn[x]-1],dep[x],tot[x]-1);
     86     for(int i=first[x];i;i=a[i].next)
     87     {
     88         int y=a[i].y;
     89         if(y==fa) continue;
     90         build_tree(y,x);
     91     }
     92 }
     93 
     94 void output(int x,int l,int r)
     95 {
     96     printf("x = %d l = %d  r = %d  lc = %d  rc = %d  sum = %d
    ",x,l,r,t[x].lc,t[x].rc,t[x].sum);
     97     int mid=(l+r)/2;
     98     if(t[x].lc) output(t[x].lc,l,mid);
     99     if(t[x].rc) output(t[x].rc,mid+1,r);
    100 }
    101 
    102 int main()
    103 {
    104     // freopen("a.in","r",stdin);
    105     freopen("tree.in","r",stdin);
    106     freopen("tree.out","w",stdout);
    107     scanf("%d%d",&n,&m);
    108     num=0;tl=0;len=0;
    109     memset(first,0,sizeof(first));
    110     for(int i=1;i<n;i++)
    111     {
    112         int x,y;
    113         scanf("%d%d",&x,&y);
    114         ins(x,y);
    115         ins(y,x);
    116     }
    117     dfs(1,0);
    118     root[0]=0;t[0].lc=t[0].rc=0;
    119     build_tree(1,0);
    120     LL ans;int p,k;
    121     for(int i=1;i<=m;i++)
    122     {
    123         scanf("%d%d",&p,&k);
    124         ans=((LL)minn(dep[p]-1,k))*((LL)(tot[p]-1));
    125         ans+=query(root[dfn[p]],root[edfn[p]],minn(n,dep[p]+1),minn(n,dep[p]+k),1,n);
    126         printf("%lld
    ",ans);
    127     }
    128     return 0;
    129 }
  • 相关阅读:
    Docker 设置阿里云镜像
    Linux 安装Navicat Premium 15
    Ubuntu常用工具安装
    Docker安装MongoDB、MySQL、Jenkins、Gitlab、Nginx
    Ubuntu18.04修改apt-get源
    Spring定时任务
    Quartz学习总结
    cron表达式
    将VirtualBox里安装的虚拟机在后台运行方法(在状态栏隐藏窗口)
    npm小结
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6035893.html
Copyright © 2011-2022 走看看