zoukankan      html  css  js  c++  java
  • 1109解题报告

    【概述】

    现场A掉T1和T2,T3骗了10分,总共210,若这是2016的NOIP试题,恐怕要跪。

    这次的题难度似乎是倒过来的,T3应该是最简单的,而T2是最难的。

    但是我一直在啃T2,以至于最后放弃了T3。

    这启示着我们,先把所有题读完是多么的重要。

    T1、prime

    【题目大意】

    给你一个区间,求区间内素数的个数。

    【吐槽】

    正解:先筛出50000以内的素数,然后在用这些素数将区间内的合数筛掉。

    我的江湖解法:看到这题,我不禁想说这不是Rabin_Miller的模板吗,于是果断敲了一遍,顺利AC,但是比正解要慢很多。

     1 /*************
     2   T1 prime
     3   by chty
     4   2016.11.9
     5 *************/
     6 #include<iostream>
     7 #include<cstdio>
     8 #include<cstring>
     9 #include<cstdlib>
    10 #include<ctime>
    11 #include<cmath>
    12 #include<algorithm>
    13 using namespace std;
    14 #define FILE "prime"
    15 typedef long long ll;
    16 const ll prime[10]={2,3,5,7,11,13,17,19,23};
    17 ll l,r,ans;
    18 inline ll read()
    19 {
    20     ll x=0,f=1;  char ch=getchar();
    21     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
    22     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
    23     return x*f;
    24 }
    25 ll fast(ll a,ll b,ll mod) {ll sum=1;for(;b;b>>=1,a=a*a%mod)if(b&1)sum=sum*a%mod;return sum;}
    26 bool Rabin_Miller(ll p,ll a)
    27 {
    28     if(p==2)  return 1;
    29     if(!(p&1)||p==1)  return 0;
    30     ll d=p-1;
    31     while(!(d&1))  d>>=1;
    32     ll m=fast(a,d,p);
    33     if(m==1)  return 1;
    34     for(;d<p;d<<=1,m=m*m%p)  if(m==p-1)  return 1;
    35     return 0;
    36 }
    37 bool isprime(ll x)
    38 {
    39     for(ll i=0;i<9;i++)
    40     {
    41         if(x==prime[i])  return 1;
    42         if(!Rabin_Miller(x,prime[i]))  return 0;  
    43     }
    44     return 1;
    45 }
    46 int main()
    47 {
    48     freopen(FILE".in","r",stdin);
    49     freopen(FILE".out","w",stdout);
    50     l=read();  r=read();
    51     for(ll i=l;i<=r;i++)  if(isprime(i))  ans++;
    52     printf("%lld
    ",ans);
    53     return 0;
    54 }

    T2、sky

    【题目大意】

    给出N个非负整数。对于区间[l,r],求

    sigma(|h[i]-x|)   (1<=i<=r)  的最小值。

    其中x为某一整数。

    【吐槽】

    一眼发现x就是这个区间的中位数,保险起见,我还证明了一遍。。。

    然后发现m很大,n很小,但n*m会超时,这让我想到了莫队算法。

    转移:对于区间[l,r],若加入一个数,则中位数可能发生变化,这时我们定义一个偏移量d,即新的中位数val与原中位数last的差值。则新的答案就是ans+d+(h[i]-val),删除也是一样的。

    (注:是否计算偏移量和当前区间元素个数有关,具体看代码)

    那么问题就来了:如何维护这个中位数?

    ——使用平衡树

    每次把元素插入到treap中,然后中位数就是treap中的第cnt/2+1大的元素,cnt为当前treap中元素的个数。

    这样就完美解决了。时间复杂度:O(m*n^0.5*logn) 

      1 /************
      2   T2 sky
      3   by chty
      4   2016.11.9
      5 ************/
      6 #include<iostream>
      7 #include<cstdio>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<ctime>
     11 #include<cmath>
     12 #include<algorithm>
     13 using namespace std;
     14 #define FILE "sky"
     15 typedef long long ll;
     16 struct node{ll l,r,id;}q[200010];
     17 struct data{ll l,r,v,size,fix,w;}tr[2000100];
     18 ll n,m,cnt,sum,block,last(-1),len,root,ans,a[200010];
     19 bool cmp(node a,node b) {if(a.l/block!=b.l/block) return a.l/block<b.l/block;return a.r<b.r;}
     20 void update(ll k){tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;}
     21 void rturn(ll &k){ll t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;tr[t].size=tr[k].size;update(k);k=t;}
     22 void lturn(ll &k){ll t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;tr[t].size=tr[k].size;update(k);k=t;}
     23 inline ll read()
     24 {
     25     ll x=0,f=1;  char ch=getchar();
     26     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
     27     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
     28     return x*f;
     29 }
     30 void insert(ll &k,ll x)
     31 {
     32     if(k==0){len++;k=len;tr[k].size=tr[k].w=1;tr[k].v=x;tr[k].fix=rand();return;}
     33     tr[k].size++;
     34     if(tr[k].v==x)tr[k].w++;
     35     else if(x>tr[k].v){insert(tr[k].r,x);if(tr[tr[k].r].fix<tr[k].fix)lturn(k);}
     36     else {insert(tr[k].l,x);if(tr[tr[k].l].fix<tr[k].fix)rturn(k);} 
     37 }
     38 void del(ll &k,ll x)
     39 {
     40     if(k==0)return; 
     41     if(tr[k].v==x)
     42     {
     43         if(tr[k].w>1){tr[k].w--;tr[k].size--;return;}
     44         if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
     45         else if(tr[tr[k].l].fix<tr[tr[k].r].fix) rturn(k),del(k,x);
     46         else lturn(k),del(k,x);
     47     }
     48     else if(x>tr[k].v) tr[k].size--,del(tr[k].r,x);
     49     else tr[k].size--,del(tr[k].l,x);
     50 }
     51 ll Findkth(ll k,ll x)
     52 {
     53     if(k==0)return 0;
     54     if(x<=tr[tr[k].l].size) return Findkth(tr[k].l,x);
     55     else if(x>tr[tr[k].l].size+tr[k].w) return Findkth(tr[k].r,x-tr[tr[k].l].size-tr[k].w);
     56     else return tr[k].v;
     57 }
     58 void add(ll x)
     59 {
     60     insert(root,x);  cnt++;
     61     ll val=Findkth(root,cnt/2+1);
     62     if(last<0)  last=val;
     63     if(val==last) sum+=abs(x-val);
     64     else 
     65     {
     66         if(!(cnt&1)) sum+=abs(val-last);
     67         last=val;
     68         sum+=abs(x-val);
     69     }
     70 }
     71 void Delete(ll x)
     72 {
     73     del(root,x);  cnt--;
     74     ll val=Findkth(root,cnt/2+1);
     75     if(val==last)  sum-=abs(x-val);
     76     else
     77     {
     78         if(!(cnt&1)) sum+=abs(val-last);
     79         last=val;
     80         sum-=abs(x-val);
     81     }
     82 }
     83 int main()
     84 {
     85     freopen(FILE".in","r",stdin);
     86     freopen(FILE".out","w",stdout);
     87     n=read();  m=read();  block=(ll)sqrt(n*1.0);
     88     for(ll i=1;i<=n;i++)  a[i]=read();
     89     for(ll i=1;i<=m;i++)  q[i].l=read(),q[i].r=read(),q[i].id=i;
     90     sort(q+1,q+m+1,cmp);
     91     ll left=1,right=0;
     92     for(ll i=1;i<=m;i++)
     93     {
     94         while(right<q[i].r)  add(a[++right]);
     95         while(right>q[i].r)  Delete(a[right--]);
     96         while(left<q[i].l)   Delete(a[left++]);
     97         while(left>q[i].l)   add(a[--left]);
     98         ans+=sum;
     99     }
    100     printf("%lld
    ",ans);
    101     return 0;
    102 }

    T3、tree

    这是UOJ上的一道题。

    AC通道:http://uoj.ac/problem/67

    调完T2便只剩10分钟了,匆匆骗了10分。

    下午写正解时调了半天,最后发现构建邻接表的代码写错了。。。(感觉NOIP药丸)

    【正解】

    求出图中的割点,标记一下,然后找到图中度数为m-n+2的点,如果这个点不是割点,那么就是题目要求的点。

    注意此题的坑:如果图中有一个点是一个独立的连通块而剩下部分是棵树,那么这个点也符合题意,这种情况我们需要特判一下。

     1 /************
     2   T3 tree
     3   by chty
     4   2016.11.9
     5 ************/
     6 #include<iostream>
     7 #include<cstdio>
     8 #include<cstdlib>
     9 #include<cstring>
    10 #include<ctime>
    11 #include<cmath>
    12 #include<algorithm>
    13 using namespace std;
    14 #define FILE "tree"
    15 #define cmin(a,b) a=min(a,b)
    16 typedef long long ll;
    17 struct node{ll y,next;}e[100010*2];
    18 ll n,m,len,cnt,dfs_clock,ans[100010],OK[100010],in[100010],Link[100010],out[100010],dfn[100010],low[100010],vis[100010];
    19 inline ll read()
    20 {
    21     ll x=0,f=1;  char ch=getchar();
    22     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
    23     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
    24     return x*f;
    25 }
    26 void insert(ll x,ll y){e[++len].next=Link[x];Link[x]=len;e[len].y=y;in[y]++;}
    27 void tarjan(int x,int fa,int root)
    28 {
    29     dfn[x]=low[x]=++dfs_clock;
    30     for(int i=Link[x];i;i=e[i].next) if(e[i].y!=fa)
    31     {
    32         if(!dfn[e[i].y])
    33         {
    34             out[x]++;
    35             tarjan(e[i].y,x,root);
    36             low[x]=min(low[x],low[e[i].y]);
    37             if(low[e[i].y]>=dfn[x])  vis[x]=1;
    38         }
    39         else low[x]=min(low[x],dfn[e[i].y]);
    40     }
    41     if(m-in[x]!=n-2)  vis[x]=1;
    42     if(out[x]==1&&x==root&&m-in[x]==n-2)  vis[x]=0;
    43 }
    44 int main()
    45 {
    46     freopen(FILE".in","r",stdin);
    47     freopen(FILE".out","w",stdout);
    48     n=read();  m=read();
    49     for(ll i=1;i<=m;i++) {ll x=read(),y=read(); insert(x,y); insert(y,x);}
    50     for(int i=1;i<=n;i++)  if(!dfn[i])  tarjan(i,0,i);
    51     for(int i=1;i<=n;i++)  if(!vis[i])  ans[++cnt]=i;
    52     printf("%lld
    ",cnt);
    53     for(int i=1;i<=cnt;i++)  printf("%lld ",ans[i]);
    54     printf("
    ");
    55     return 0;
    56 }
  • 相关阅读:
    JavaScript中{}+{}
    网站性能优化
    C++是如何从代码到游戏的?
    C++是如何从代码到游戏的?
    【力扣】至少是其他数字两倍的最大数 中速题解
    代码编辑器选择Atom还是VScode?
    TIOBE 4 月榜单:少儿编程语言 Scratch 进入 TOP 20
    熟悉一下oncontextmenu事件的知识
    input属性type为file打开文件资源管理器时,如何限制多次选取或只能一次选取的行为
    HTML5的拖放事件
  • 原文地址:https://www.cnblogs.com/chty/p/6047873.html
Copyright © 2011-2022 走看看