首页 > 代码库 > 1109解题报告

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\n",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\n",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\n",cnt);
53     for(int i=1;i<=cnt;i++)  printf("%lld ",ans[i]);
54     printf("\n");
55     return 0;
56 }

 

1109解题报告