20180213小测

20180213小测

上了几天课后,我么迎来了秦神的考试……

上次秦神出题T1T3集体爆零的心里阴影还没有褪去QAQ……

T1:

说白了就是让你在原串中选出一些子串使之价值和最大,已经被删去的子串使得区间两端合并。

首先注意这题是子串而不是子序列。考试的时候我当子序列做了半天,什么贪心、DP、网络流全都试了一遍,发现根本不可做,连爆搜都不会写……

然而看到这题这样就肯定是区间DP了,因为我们选择的是一个子串,所以对于一个我们要选出的串,他要么在原串中连续出现,要么在原串中分开出现且间隔部分可以全部被选出。

所以我们令f[i][j][p][k]表示原串区间[i,j],匹配目标串p,第i位匹配第1位,第j维匹配第k位,dp[i][j]表示原串[i,j]能否被完全选出(先别管我为什么这么定义,一会看转移就明白了QAQ)。

我们考虑串p的位置k-1匹配的位置。我们在区间[I,j)枚举l,表示第k-1位匹配的位置。

若l==k-1,则中间没有间隔串,f[i][j][p][k]从f[i][l][p][k-1]转移。

若l!=k-1,说明中间间隔了一些部分且他们必须完全消去,所以我们让f[i][j][p][k]从f[i][l][p][k-1]&&dp[l+1][j]转移。

对于dp数组,一个能完全选出的区间要么由两边两个能完全选出的区间组成,要么恰好完美匹配某个目标串,我们枚举一下分割位置或者匹配的目标串即可。

复杂度?f的转移把[p][k]摊还下来是O(n^4)的,且为区间DP,有一个最大1/8的常数。dp的转移只用枚举中间位置或匹配串,复杂度O(n^3)。实测跑得飞快。

然而这题限制64mb内存,你直接开会MLE。用vector进行动态resize依旧会MLE(亲测还会TLE)。你需要开出f[i][j][p]的指针,最后一维k用C++的new分配内存就好了。

关于答案统计,我们可以看做在区间内选择几条有权值且不相同的线段覆盖,做线段覆盖就好了。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define bool unsigned char
 5 const int maxn=1e2+1e1,maxl=1.5e2+1e1;
 6 
 7 char in[maxl],tar[maxn][maxl];
 8 int val[maxn],sum[maxl],lt[maxn],g[maxl]; 
 9 bool* f[maxl][maxl][maxn];
10 bool dp[maxl][maxl];
11 int n,li;
12 
13 inline void getans() {
14     for(int len=1;len<=li;len++)
15         for(int st=1;st+len-1<=li;st++) {
16             const int ed = st + len - 1;
17             for(int p=1;p<=n;p++) { // p is the pairing string .
18                 for(int k=1;k<=lt[p]&&k<=len;k++) {
19                     if( in[ed] != tar[p][k] ) continue;
20                     if( k == 1 ) {
21                         if( st == ed ) f[st][ed][p][k] = 1;
22                         else f[st][ed][p][k] = dp[st][ed-1];
23                         continue;
24                     }
25                     for(int l=st;l<ed;l++) {
26                         if( l == ed - 1 ) f[st][ed][p][k] |= f[st][l][p][k-1];
27                         else f[st][ed][p][k] |= f[st][l][p][k-1] && dp[l+1][ed-1];
28                     }
29                 }
30             }
31             for(int mid=st;mid<ed;mid++)
32                 dp[st][ed] |= ( dp[st][mid] && dp[mid+1][ed] );
33             for(int p=1;p<=n;p++)
34                 dp[st][ed] |= f[st][ed][p][lt[p]];
35         }
36     for(int i=0;i<=li;i++) { // g[i] is proccessed
37         if( i ) g[i] = std::max( g[i] , g[i-1] );
38         for(int ed=i+1;ed<=li;ed++)
39             if( dp[i+1][ed] ) g[ed] = std::max( g[ed] , g[i] + sum[ed] - sum[i] );
40     }
41 }
42 inline void readin() {
43     static int k,p;
44     static char s[maxl];
45     scanf("%d",&k);
46     while( k-- ) {
47         scanf("%s%d",s,&p);
48         val[(int)*s-'a'] = p;
49     }
50     scanf("%s",in+1) , li = strlen(in+1);
51     for(int i=1;i<=li;i++) sum[i] = sum[i-1] + val[(int)in[i]-'a'];
52     scanf("%d",&n);
53     for(int i=1;i<=n;i++) {
54         scanf("%s",tar[i]+1);
55         lt[i] = strlen(tar[i]+1);
56         for(int j=1;j<=li;j++)
57             for(int k=1;k<=li;k++) {
58                 f[j][k][i] = new bool [lt[i]+1];
59                 for(int p=0;p<=lt[i];p++)
60                     f[j][k][i][p] = 0;
61             }
62     }
63 }
64 
65 int main() {
66     readin();
67     getans();
68     printf("%d
",g[li]);
69     return 0;
70 }
View Code

T2:

关于题意:如果若干个点全都距离很近能相互到达,使得能到达每家店的数量大于等于k,则全部关门。

我们把距离转成切比雪夫距离,那么一家店能到达的店在一个矩形内。我们只用统计出一家店能被多少家到达,就可以知道他是否需要关门。

二维数据结构随便做啊,然而64mb内存卡树套树,懒得调扫描线或分治。考虑n只有10w,分块的数据范围,所以好写好调的kdtree随便过啊。

我们对于每个节点记录这个节点被完整覆盖了多少遍,最后再把树dfs一遍好了。统计答案的时候别忘了减去自身对自身的贡献。

码了十几分钟考场一发AC,话说这题为什么就我一个拿分的?别人都写跪了?

代码:

 1 #pragma GCC optimize(3)
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define lli long long int
 7 #define debug cout
 8 using namespace std;
 9 const int maxn=1e5+1e2;
10 
11 int cmp;
12 struct Point {
13     int d[2],id; // 0 means x , 1 means y .
14     friend bool operator < (const Point &a,const Point &b) {
15         return a.d[cmp] < b.d[cmp];
16     }
17 }ps[maxn],nv[maxn];
18 int lson[maxn],rson[maxn],mx[maxn][2],mi[maxn][2],lazy[maxn],cnt;
19 int inx[maxn],iny[maxn],ind[maxn],ans[maxn];
20 
21 inline void fill(int pos,const Point &p) {
22     nv[pos] = p;
23     for(int i=0;i<2;i++)
24         mx[pos][i] = mi[pos][i] = p.d[i];
25 }
26 inline void update(int fa,int son) {
27     if( !son ) return;
28     for(int i=0;i<2;i++)
29         mx[fa][i] = max( mx[fa][i] , mx[son][i] ) ,
30         mi[fa][i] = min( mi[fa][i] , mi[son][i] );
31 }
32 inline void build(int pos,int dir,int l,int r) {
33     const int mid = ( l + r ) >> 1;
34     cmp = dir;
35     nth_element(ps+l,ps+mid,ps+r+1);
36     fill(pos,ps[mid]);
37     if( l < mid ) build(lson[pos]=++cnt,dir^1,l,mid-1);
38     if( mid < r ) build(rson[pos]=++cnt,dir^1,mid+1,r);
39     update(pos,lson[pos]) , update(pos,rson[pos]);
40 }
41 inline bool insqr(int p,int sx,int tx,int sy,int ty) {
42     return sx <= mi[p][0] && mx[p][0] <= tx
43         && sy <= mi[p][1] && mx[p][1] <= ty;
44 }
45 inline bool insqr(const Point &p,int sx,int tx,int sy,int ty) {
46     return sx <= p.d[0] && p.d[0] <= tx
47         && sy <= p.d[1] && p.d[1] <= ty;
48 }
49 inline bool outsqr(int p,int sx,int tx,int sy,int ty) {
50     return mx[p][0] < sx || tx < mi[p][0]
51         || mx[p][1] < sy || ty < mi[p][1];
52 }
53 inline void update(int pos,int sx,int tx,int sy,int ty) {
54     if( !pos || outsqr(pos,sx,tx,sy,ty) ) return;
55     if( insqr(pos,sx,tx,sy,ty) ) {
56         ++lazy[pos];
57         return;
58     }
59     if( insqr(nv[pos],sx,tx,sy,ty) ) ans[nv[pos].id]++;
60     update(lson[pos],sx,tx,sy,ty) , update(rson[pos],sx,tx,sy,ty);
61 }
62 inline void dfs(int pos) {
63     ans[nv[pos].id] += lazy[pos];
64     if( lson[pos] ) lazy[lson[pos]] += lazy[pos] , dfs(lson[pos]);
65     if( rson[pos] ) lazy[rson[pos]] += lazy[pos] , dfs(rson[pos]);
66 }
67 
68 int main() {
69     static int n,k,cn;
70     scanf("%d%d",&n,&k);
71     for(int i=1,x,y;i<=n;i++) {
72         scanf("%d%d%d",&x,&y,ind+i);
73         inx[i] = x + y , iny[i] = x - y;
74         ps[i] = (Point){ { inx[i] , iny[i] } , i };
75     }
76     build(cnt=1,0,1,n);
77     for(int i=1;i<=n;i++) {
78         update(1,
79         max((lli)inx[i]-ind[i],-2147483648ll),
80         min((lli)inx[i]+ind[i],2147483647ll),
81         max((lli)iny[i]-ind[i],-2147483648ll),
82         min((lli)iny[i]+ind[i],2147483647ll));
83     }
84     dfs(1);
85     for(int i=1;i<=n;i++) cn += ( ans[i] > k );
86     printf("%d
",cn);
87     for(int i=1;i<=n;i++) if( ans[i] > k ) printf("%d ",i);
88     puts("");
89     return 0;
90 }
View Code

T3:

不能相互到达?不就是最大独立集?点数减最大匹配就好了。

等等,一般图最大匹配?这不是经典的NP问题吗?这题能做?

发现按照行列分组后这是一个二分图,然后就拿到了48分……

这个思路为什么有问题呢?因为一旦n为奇数的话,这图存在奇环,就不是二分图了……

根据鸽笼原理,一定有一行点数<=10,我们暴力枚举这一行状态,剩下的就是二分图了。

说着简单写着难系列。

考场48分代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<queue>
  7 #define debug cout
  8 using namespace std;
  9 const int maxn=2e2+1e1,maxm=maxn*maxn,maxe=55;
 10 const int inf=0x3f3f3f3f;
 11 
 12 int k[maxe],sum[maxn],n,full;
 13 int st,ed;
 14 
 15 struct Elevator {
 16     int h,x,y;
 17     friend bool operator < (const Elevator &a,const Elevator &b) {
 18         if( a.h != b.h ) return a.h < b.h;
 19         if( a.x != b.x ) return a.x < b.x;
 20         return a.y < b.y;
 21     }
 22     friend bool operator == (const Elevator &a,const Elevator &b) {
 23         return a.h == b.h && a.x == b.x && a.y == b.y;
 24     }
 25 };
 26 vector<Elevator> v;
 27 
 28 namespace Flow {
 29     int s[maxn],t[maxm<<1],nxt[maxm<<1],f[maxm<<1],dep[maxn];
 30     
 31     inline void coredge(int from,int to,int flow) {
 32         static int cnt = 1;
 33         t[++cnt] = to , f[cnt] = flow ,
 34         nxt[cnt] = s[from] , s[from] = cnt;
 35     }
 36     inline void singledge(int from,int to,int flow) {
 37         coredge(from,to,flow) , coredge(to,from,0);
 38     }
 39     inline bool bfs() {
 40         memset(dep,-1,sizeof(dep)) , dep[st] = 0;
 41         queue<int> q; q.push(st);
 42         while( q.size() ) {
 43             const int pos = q.front(); q.pop();
 44             for(int at=s[pos];at;at=nxt[at]) {
 45                 if( f[at] && !~dep[t[at]] ) dep[t[at]] = dep[pos] + 1 , q.push(t[at]);
 46             }
 47         }
 48         return ~dep[ed];
 49     }
 50     inline int dfs(int pos,int flow) {
 51         if( pos == ed ) return flow;
 52         int ret = 0 , now = 0;
 53         for(int at=s[pos];at;at=nxt[at])
 54             if( f[at] && dep[t[at]] > dep[pos] ) {
 55                 now = dfs(t[at],min(flow,f[at]));
 56                 ret += now , flow -= now ,
 57                 f[at] -= now , f[at^1] += now;
 58                 if( !flow ) return ret;
 59             }
 60         if( !ret ) dep[pos] = -1;
 61         return ret;
 62     }
 63     inline int dinic() {
 64         int ret = 0 , now = 0;
 65         while( bfs() ) {
 66             while( ( now = dfs(st,inf) ) ) ret += now;
 67         }
 68         return ret;
 69     }
 70 }
 71 
 72 inline int covdep(int dep,int pos) {
 73     return sum[dep-1] + pos;
 74 }
 75 inline int cov(int id,int tpe) { // tpe == 0 means out point , 1 means in point
 76     return id * 2 + tpe - 1;
 77 }
 78 
 79 inline void pre() {
 80     sort(v.begin(),v.end());
 81     unsigned len = unique(v.begin(),v.end()) - v.begin();
 82     for(int i=1;i<=n;i++) sum[i] = sum[i-1] + k[i];
 83     full = sum[n] , st = full * 2 + 1 , ed = full * 2 + 2;
 84     for(unsigned i=0;i<len;i++) {
 85         const int x = covdep(v[i].h,v[i].x);
 86         const int y = covdep(v[i].h!=n?v[i].h+1:1,v[i].y);
 87         if( v[i].h & 1 ) {
 88             Flow::singledge(cov(x,1),cov(y,0),1);
 89         } else {
 90             Flow::singledge(cov(y,1),cov(x,0),1);
 91         }
 92     }
 93     for(int i=1;i<=full;i++)
 94         Flow::singledge(cov(i,0),cov(i,1),1);
 95     for(int i=1;i<=n;i++)
 96         if( i & 1 ) {
 97             for(int j=1;j<=k[i];j++)
 98                 Flow::singledge( st , cov(sum[i-1]+j,0) , 1 );
 99         } else {
100             for(int j=1;j<=k[i];j++)
101                 Flow::singledge( cov(sum[i-1]+j,1) , ed , 1 );
102         }
103 }
104 
105 int main() {
106     static int h,x,y,ans;
107     scanf("%d",&n);
108     int t = 0;
109     while( scanf("%d%d%d",&x,&y,&h) == 3 ) {
110         v.push_back((Elevator){h,x,y});
111         k[h] = max( k[h] , x ) , k[h!=n?h+1:1] = max( k[h!=n?h+1:1] , y );
112         ++t;
113     }
114     pre();
115     ans = full - Flow::dinic();
116     printf("%d
",ans);
117     return 0;
118 }
View Code

考后AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<queue>
  7 #define debug cout
  8 using namespace std;
  9 const int maxn=2e2+1e1,maxm=4e4+1e2,maxe=55;
 10 const int inf=0x3f3f3f3f;
 11 
 12 int k[maxe],sum[maxn],n,full,mip,ans;
 13 int st,ed,len;
 14 bool vis[maxn];
 15 
 16 struct Elevator {
 17     int h,x,y;
 18     friend bool operator < (const Elevator &a,const Elevator &b) {
 19         if( a.h != b.h ) return a.h < b.h;
 20         if( a.x != b.x ) return a.x < b.x;
 21         return a.y < b.y;
 22     }
 23     friend bool operator == (const Elevator &a,const Elevator &b) {
 24         return a.h == b.h && a.x == b.x && a.y == b.y;
 25     }
 26 };
 27 vector<Elevator> v;
 28 
 29 namespace Flow {
 30     int s[maxn],t[maxm<<1],nxt[maxm<<1],f[maxm<<1],dep[maxn],cnt=1;
 31     
 32     inline void coredge(int from,int to,int flow) {
 33         t[++cnt] = to , f[cnt] = flow ,
 34         nxt[cnt] = s[from] , s[from] = cnt;
 35     }
 36     inline void singledge(int from,int to,int flow) {
 37         coredge(from,to,flow) , coredge(to,from,0);
 38     }
 39     inline bool bfs() {
 40         memset(dep,-1,sizeof(dep)) , dep[st] = 0;
 41         queue<int> q; q.push(st);
 42         while( q.size() ) {
 43             const int pos = q.front(); q.pop();
 44             for(int at=s[pos];at;at=nxt[at]) {
 45                 if( f[at] && !~dep[t[at]] ) dep[t[at]] = dep[pos] + 1 , q.push(t[at]);
 46             }
 47         }
 48         return ~dep[ed];
 49     }
 50     inline int dfs(int pos,int flow) {
 51         if( pos == ed ) return flow;
 52         int ret = 0 , now = 0;
 53         for(int at=s[pos];at;at=nxt[at])
 54             if( f[at] && dep[t[at]] > dep[pos] ) {
 55                 now = dfs(t[at],min(flow,f[at]));
 56                 ret += now , flow -= now ,
 57                 f[at] -= now , f[at^1] += now;
 58                 if( !flow ) return ret;
 59             }
 60         if( !ret ) dep[pos] = -1;
 61         return ret;
 62     }
 63     inline int dinic() {
 64         int ret = 0 , now = 0;
 65         while( bfs() )
 66             while( ( now = dfs(st,inf) ) ) ret += now;
 67         return ret;
 68     }
 69     inline void reset() {
 70         memset(s,0,sizeof(s)) , cnt = 1;
 71     }
 72 }
 73 
 74 inline int countbit(int x) {
 75     #define lowbit(x) (x&-x)
 76     int ret = 0;
 77     while( x ) ++ret , x -= lowbit(x);
 78     return ret;
 79 }
 80 inline int covdep(int dep,int pos) {
 81     return sum[dep-1] + pos;
 82 }
 83 
 84 inline int rebuild(int sta) {
 85     Flow::reset() , memset(vis,0,sizeof(vis));
 86     int ret = 0;
 87     for(int i=0;i<k[mip];i++) if( ! ( sta & ( 1 << i ) ) ) vis[covdep(mip,i+1)] = 1;
 88     for(int i=0;i<len;i++) {
 89         const int h = v[i].h , th = h != n ? h + 1 : 1;
 90         if( h == mip) {
 91             if( ( 1 << ( v[i].x - 1 ) ) & sta ) vis[covdep(th,v[i].y)] = 1;
 92         }
 93         else if( th == mip ) {
 94             if( ( 1 << ( v[i].y - 1 ) ) & sta ) vis[covdep(h,v[i].x)] = 1;
 95         }else {
 96             if( ( h > mip && ( ( h - mip ) & 1 ) ) || ( h < mip && ! ( ( mip - h ) & 1 ) ) )
 97                 Flow::singledge(covdep(h,v[i].x),covdep(th,v[i].y),1);
 98             else Flow::singledge(covdep(th,v[i].y),covdep(h,v[i].x),1);
 99         }
100     }
101     for(int i=1;i<=n;i++) {
102         if( ( i > mip && ( ( i - mip ) & 1 ) ) || ( i < mip && !( ( mip - i ) & 1 ) ) ) {
103             for(int j=1;j<=k[i];j++)
104                 if( !vis[covdep(i,j)] ) Flow::singledge(st,covdep(i,j),1);
105         } else if( i != mip ) {
106             for(int j=1;j<=k[i];j++)
107                 if( !vis[covdep(i,j)] ) Flow::singledge(covdep(i,j),ed,1);
108         }
109     }
110     for(int i=1;i<=full;i++) ret += !vis[i];
111     ret -= Flow::dinic();
112     return ret;
113 }
114 inline void getansodd() {
115     int fs = ( 1 << k[mip] );
116     for(int i=0;i<fs;i++) ans = max( ans , rebuild(i) );
117 }
118 inline void getanseven() {
119     for(int i=0;i<len;i++) {
120         const int x = covdep(v[i].h,v[i].x);
121         const int y = covdep(v[i].h!=n?v[i].h+1:1,v[i].y);
122         if( v[i].h & 1 ) Flow::singledge(x,y,1);
123         else Flow::singledge(y,x,1);
124     }
125     for(int i=1;i<=n;i++) {
126         if( i & 1 ) {
127             for(int j=1;j<=k[i];j++)
128                 Flow::singledge( st , covdep(i,j) , 1 );
129         } else {
130             for(int j=1;j<=k[i];j++)
131                 Flow::singledge( covdep(i,j) , ed , 1 );
132         }
133     }
134     ans = full - Flow::dinic();
135 }
136 
137 inline void pre() {
138     sort(v.begin(),v.end());
139     len = unique(v.begin(),v.end()) - v.begin();
140     for(int i=1;i<=n;i++) sum[i] = sum[i-1] + k[i];
141     full = sum[n] , st = full + 1 , ed = full + 2;
142     *k = inf;
143     for(int i=1;i<=n;i++) if( k[i] < k[mip] ) mip = i;
144 }
145 
146 int main() {
147     static int h,x,y;
148     scanf("%d",&n);
149     int t = 0;
150     while( scanf("%d%d%d",&x,&y,&h) == 3 ) {
151         v.push_back((Elevator){h,x,y});
152         k[h] = max( k[h] , x ) , k[h!=n?h+1:1] = max( k[h!=n?h+1:1] , y );
153         ++t;
154     }
155     pre();
156     if( n & 1 ) getansodd();
157     else getanseven();
158     printf("%d
",ans);
159     return 0;
160 }
View Code

话说在从老家回来汽车上写这东西真是晃死我了……

原文地址:https://www.cnblogs.com/Cmd2001/p/8450474.html