20171226小测
于是今天上午有了一场愉悦的考试。
这里只是来写总结和题解的。
T1(中位数之塔):
链接:EZOJ_Alpha:P1018
一道找规律题,先二分答案然后在找规律线性时间验证。
显然先通过大小比较把输入转成0、1序列。
规律是什么呢?如果有两个连续的0或者1,则他们会每次向中间错一格,最后谁先到中间那么答案就是谁。
其实就是去比较距离。
如果两者均不存在,则最下面一行一定是01间隔的,手玩一下可发现规律。
然后我是怎么挂的呢?看出两个0上面全都是0,两个1上面全都是1,然后不会做,弃坑了。
交了30分暴力,然后数组开小,爆零啦QAQ。
然后上代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=1e5+1e2; 8 9 int in[maxn<<1],nums[maxn<<1]; 10 int n,dep; 11 12 inline int findcon(int pos,int tar) { 13 int l = pos , r = pos; 14 while( l > 1 && ( nums[l]!=tar || nums[l-1]!=tar) ) 15 --l; 16 while( r < ( n * 2 - 1 ) && ( nums[r]!=tar || nums[r+1]!=tar ) ) 17 ++r; 18 return min( pos - l , r - pos ); 19 } 20 inline void cov(int x) { 21 for(int i=1;i<n<<1;i++) 22 nums[i] = ( in[i] >= x ); 23 } 24 inline bool judge(int x) { 25 cov(x); 26 int dze = findcon(n,0) , don = findcon(n,1); 27 if( dze != don ) 28 return dze > don; 29 return ! ( (dep + nums[n] ) & 1 ); 30 } 31 inline int getans() { 32 int ll = 1 , rr = ( n << 1 ) - 1 , mid; 33 while( rr != ll + 1 ) { 34 mid = ( ll + rr ) >> 1; 35 if( !judge(mid) ) 36 rr = mid; 37 else ll = mid; 38 } 39 return ll; 40 } 41 42 int main() { 43 scanf("%d",&n); 44 dep = ( n + 1 ) >> 1; 45 for(int i=1;i<n<<1;i++) 46 scanf("%d",in+i); 47 48 printf("%d\n",getans()); 49 50 return 0; 51 }
T2(宝石迷阵):
链接:EZOJ_Alpha:P1017
让符合某种条件的东西最多,显然拆点网络流。然而如何保证90度转角?
考虑转了90度的两个点一定不在同一行,按行染色即可。
考场AC。
上代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define debug cout 7 using namespace std; 8 const int maxn=5e+3+1e2,maxm=maxn*50; 9 const int inf=0x3f3f3f3f; 10 11 int s[maxn],t[maxm],nxt[maxm],f[maxm]; 12 int dep[maxn]; 13 char in[55][55]; 14 int n,m,st,ed; 15 16 inline void coredge(int from,int to,int flow) { 17 static int cnt = 1; 18 t[++cnt] = to, 19 f[cnt] = flow, 20 nxt[cnt] = s[from], 21 s[from] = cnt; 22 } 23 inline void addedge(int from,int to,int flow) { 24 coredge(from,to,flow); 25 coredge(to,from,0); 26 } 27 28 inline bool bfs() { 29 memset(dep,-1,sizeof(dep)); 30 dep[st] = 0; 31 queue<int> q; 32 q.push(st); 33 while( q.size() ) { 34 const int pos = q.front(); q.pop(); 35 for(int at=s[pos];at;at=nxt[at]) 36 if( f[at] && !~dep[t[at]] ) { 37 dep[t[at]] = dep[pos] + 1; 38 q.push(t[at]); 39 } 40 } 41 return ~dep[ed]; 42 } 43 inline int dfs(int pos,int flow) { 44 if( pos == ed ) 45 return flow; 46 int ret = 0 , now = 0; 47 for(int at=s[pos];at;at=nxt[at]) 48 if( f[at] && dep[t[at]] > dep[pos] ) { 49 now = dfs(t[at],min(flow,f[at])); 50 ret += now , flow -= now, 51 f[at] -= now , f[at^1] += now; 52 if( !flow ) 53 return ret; 54 } 55 if( !ret ) 56 dep[pos] = -1; 57 return ret; 58 } 59 inline int dinic() { 60 int ret = 0 , now = 0; 61 while( bfs() ) { 62 while( now = dfs(st,inf) ) 63 ret += now; 64 } 65 return ret; 66 } 67 68 inline int cov(int xx,int yy,int sta=0) { // 0 means full point or in point , 1 means out point. 69 return ( ( xx - 1 ) * m + yy ) * 2 - 1 + sta; 70 } 71 inline bool judge(int xx,int yy) { 72 return xx > 0 && xx <= n && yy > 0 && yy <= m && in[xx][yy]=='.'; 73 } 74 inline void explain() { 75 st = cov(n,m,1) + 1 , ed = cov(n,m,1) + 2; 76 for(int i=1;i<=n;i++) 77 for(int j=1;j<=m;j++) 78 if( in[i][j] == '.' && ( ( i + j ) & 1 ) ) { 79 if( i & 1 ) 80 addedge(st,cov(i,j),1); 81 else 82 addedge(cov(i,j),ed,1); 83 } 84 for(int i=1;i<=n;i++) 85 for(int j=1;j<=m;j++) 86 if( in[i][j] == '.' && ! ( ( i + j ) & 1 ) ) { 87 addedge(cov(i,j,0),cov(i,j,1),1); 88 if( i & 1 ) { 89 if( judge(i-1,j) ) 90 addedge(cov(i,j,1),cov(i-1,j),1); 91 if( judge(i+1,j) ) 92 addedge(cov(i,j,1),cov(i+1,j),1); 93 if( judge(i,j+1) ) 94 addedge(cov(i,j+1),cov(i,j,0),1); 95 if( judge(i,j-1) ) 96 addedge(cov(i,j-1),cov(i,j,0),1); 97 } 98 else { 99 if( judge(i-1,j) ) 100 addedge(cov(i-1,j),cov(i,j,0),1); 101 if( judge(i+1,j) ) 102 addedge(cov(i+1,j),cov(i,j,0),1); 103 if( judge(i,j+1) ) 104 addedge(cov(i,j,1),cov(i,j+1),1); 105 if( judge(i,j-1) ) 106 addedge(cov(i,j,1),cov(i,j-1),1); 107 } 108 } 109 } 110 111 int main() { 112 scanf("%d%d",&n,&m); 113 for(int i=1;i<=n;i++) 114 scanf("%s",in[i]+1); 115 116 explain(); 117 118 printf("%d\n",dinic()); 119 120 return 0; 121 }
T3(SiriusRen的卡牌):
链接:EZOJ_Alpha:P1016
首先先Orz一发SiriusRen,线段树巨佬(狂魔?)。
既然这样那么这道题就一定也是线段树了,考虑把一个属性a排序后枚举,那么对于ai小于now的i,我们需要在另外两个属性中选择一个更大;而ai大于now的i,我们需要两个属性均比他大。
用线段树维护另外两个属性(x,y)的关系,对于属性a比now小的i,(x,y)形成一个递降的阶梯。对于属性a比now大的i,对
他们的(x,y)连续取平均值形成两条线。我们对于now这个值的答案就是这些东西和(maxx,maxy)围成的面积。
线段树维护区间赋值即可。然而需要orz一发SiriusRen的写法:通过维护区间min和max简单地实现区间赋值。
我考场上怎么死的?推出来东西了,不会维护,最后28分暴力滚粗。
最后上代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lli long long int 6 #define debug cout 7 using namespace std; 8 const int maxn=5e5+1e2; 9 //New operation learnt from RYC. 10 11 struct SegmentTree { 12 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3]; 13 lli mxv[maxn<<3],miv[maxn<<3],sum[maxn<<3],lazy[maxn<<3]; 14 int cnt; 15 16 inline void build(int pos,int ll,int rr) { 17 l[pos] = ll , r[pos] = rr; 18 if( ll == rr ) 19 return; 20 const int mid = ( ll + rr ) >> 1; 21 build(lson[pos]=++cnt,ll,mid); 22 build(rson[pos]=++cnt,mid+1,rr); 23 } 24 inline void set(int pos,lli x) { 25 mxv[pos] = miv[pos] = lazy[pos] = x; 26 sum[pos] = x * ( r[pos] - l[pos] + 1 ); 27 } 28 inline void push(int pos) { 29 if( lazy[pos] ) { 30 if( lson[pos] ) 31 set(lson[pos],lazy[pos]); 32 if( rson[pos] ) 33 set(rson[pos],lazy[pos]); 34 lazy[pos] = 0; 35 } 36 } 37 inline void up(int pos) { 38 sum[pos] = sum[lson[pos]] + sum[rson[pos]]; 39 mxv[pos] = max( mxv[lson[pos]] , mxv[rson[pos]] ); 40 miv[pos] = min( miv[lson[pos]] , miv[rson[pos]] ); 41 } 42 inline void update(int pos,int ll,int rr,lli x) { 43 if( rr < l[pos] || r[pos] < ll || x <= miv[pos] ) 44 return; 45 if( ll <= l[pos] && r[pos] <= rr && x >= mxv[pos] ) { 46 set(pos,x); 47 return; 48 } 49 push(pos); 50 update(lson[pos],ll,rr,x); 51 update(rson[pos],ll,rr,x); 52 up(pos); 53 } 54 inline lli full() { 55 return sum[1]; 56 } 57 inline lli query(int pos,int ll,int rr) { 58 if( rr < l[pos] || r[pos] < ll ) 59 return 0; 60 if( ll <= l[pos] && r[pos] <= rr ) 61 return sum[pos]; 62 push(pos); 63 return query(lson[pos],ll,rr) + query(rson[pos],ll,rr); 64 } 65 }st; 66 67 struct Node { 68 int zz,xx,yy; 69 friend bool operator < (const Node &a,const Node &b) { 70 return a.zz < b.zz; 71 } 72 }ns[maxn]; 73 74 lli zz,xx,yy,ans; 75 int n; 76 77 inline void init() { 78 sort(ns+1,ns+1+n); 79 st.build(st.cnt=1,1,xx); 80 } 81 82 inline void getans() { 83 for(int i=1;i<=n;i++) 84 st.update(1,1,ns[i].xx,ns[i].yy); 85 for(int i=zz,j=n;i;i--) { 86 while( ns[j].zz == i ) { 87 st.update(1,1,xx,ns[j].yy); 88 st.update(1,1,ns[j].xx,yy); 89 j--; 90 } 91 ans += xx * yy - st.query(1,1,xx); 92 } 93 } 94 95 int main() { 96 scanf("%d%lld%lld%lld",&n,&zz,&xx,&yy); 97 for(int i=1;i<=n;i++) 98 scanf("%d%d%d",&ns[i].zz,&ns[i].xx,&ns[i].yy); 99 100 init(); 101 getans(); 102 103 printf("%lld\n",ans); 104 105 return 0; 106 }
最后关于为什么我管这个OJ叫EZOJ_Alpha?
因为我曾经建立过一个局域网专用的基于HUSTOJ的EZOJ,上面有200+题,1k+评测记录,然后被我不小心rm -rf /*了......