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上的一道题。
调完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 }