20180225小测

今天早晨一来就是一场猝不及防的考试(说好的下午考呢?)
于是没有打卡(其实打了也是模拟赛爆零)

T1:

这题一看不可做啊......
数据范围显然是nlogn,大概复杂度全都在排序。
好,我们开始推结论什么的,一个人能感染到的人一定是前面比他快或者后面比他慢。
然后呢?感染有时间顺序,所以我们能按照时间建图,存在点数O(n^3)的大力DP。
but,多个人同时相遇怎么办?不会DP了,弃坑弃坑。
写了10分爆搜然后写挂爆零了。
关于这题正解?
如果我们让时间趋于正无穷,那么这些人的顺序一定是按照速度排序的。
考虑一个人能感染那些人?起始点在他前且速度比他快的,起始点在他后且比他慢的。
那么,每个人在这个序列上能感染的区间就是[起始点比在他后的人且比他慢的中最慢的,起始点在他前的人且比他快的中最快的]。
为什么?显然这个区间外的人都不能被感染(那些人一定是在前且慢或者在后且块)。
对于区间内速度大于当前点的点,如果速度比右端点慢且在初始位置当前点右,那么他会被已经被感染的右端点感染。
如果速度比左端点慢且初始位置在左,那么因为他比当前点快,一定会被当前点直接感染。
左边情况同理。

考场爆零代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 const int maxn=17;
 6 const double eps=1e-8;
 7 
 8 struct Node {
 9     double t;
10     int u,v;
11     Node() {}
12     Node(double tt,int uu,int vv) { t = tt , u = uu , v = vv ; }
13     friend bool operator < (const Node &a,const Node &b) {
14         return a.t < b.t;
15     }
16 }ns[maxn*maxn];
17 
18 int x[maxn],v[maxn],used[maxn],vis[maxn],n,cnt,ans;
19 
20 inline void gnode(int a,int b) {
21     if( x[a] < x[b] && v[a] < v[b] ) return;
22     ns[++cnt] = Node((double)(x[b]-x[a])/(v[a]-v[b]),a,b);
23 }
24 inline void check() {
25     memcpy(vis+1,used+1,sizeof(int)*n);
26     for(int i=1,j,tp;i<=cnt;i=j+1) {
27         j = i , tp = 0;
28         while( j < cnt && std::fabs(ns[j+1].t-ns[i].t) <= eps ) ++j;
29         for(int k=i;k<=j;k++) tp |= ( vis[ns[k].u] | vis[ns[k].v] );
30         for(int k=i;k<=j;k++) vis[ns[k].u] |= tp , vis[ns[k].v] |= tp;
31     }
32     for(int i=1;i<=n;i++) if( !vis[i] ) return;
33     ++ans;
34 }
35 inline void dfs(int pos) {
36     if( pos > n ) return check();
37     used[pos] = 0 , dfs( pos + 1 ) ,
38     used[pos] = 1 , dfs( pos + 1 ) ;
39 }
40 
41 int main() {
42     scanf("%d",&n);
43     for(int i=1;i<=n;i++) scanf("%d%d",x+i,v+i);
44     for(int i=1;i<=n;i++)
45         for(int j=i+1;j<=n;j++)
46             gnode(i,j);
47     std::sort(ns+1,ns+1+cnt);
48     dfs(1);
49     printf("%d
",ans);
50     return 0;
51 }
View Code

考后AC代码:

 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=2e5+1e2;
 9 const int mod = 1e9 + 7;
10 
11 struct Person {
12     int s,v,id;
13     friend bool operator < (const Person &a,const Person &b) {
14         return a.v < b.v;
15     }
16 }ns[maxn];
17 
18 
19 struct Segment {
20     int l,r;
21     friend bool operator < (const Segment &a,const Segment &b) {
22         return a.r != b.r ? a.r < b.r : a.l < b.l;
23     }
24 }ss[maxn];
25 
26 int mov[maxn];
27 lli ff[maxn],sum[maxn],pows[maxn],*f;
28 
29 inline bool cmp(const Person &a,const Person &b) {
30     return a.s < b.s;
31 }
32 
33 int main() {
34     static int n;
35     scanf("%d",&n);
36     for(int i=1;i<=n;i++) scanf("%d%d",&ns[i].s,&ns[i].v);
37     sort(ns+1,ns+1+n,cmp);
38     for(int i=1;i<=n;i++) ns[i].id = i;
39     sort(ns+1,ns+1+n);
40     for(int i=1;i<=n;i++) mov[ns[i].id] = i;
41     sort(ns+1,ns+1+n,cmp);
42     int m = 0;
43     for(int i=1;i<=n;i++) {
44         m = max( m , mov[i] );
45         ss[i].r = m;
46     }
47     m = n+1;
48     for(int i=n;i;i--) {
49         m = min( m , mov[i] );
50         ss[i].l = m;
51     }
52     sort(ss+1,ss+1+n);
53     *pows = 1 , f = ff + 1;
54     for(int i=1;i<=n;i++) pows[i] = pows[i-1] * 2 % mod;
55     *f = *sum = 1;
56     for(int i=1,l=1,r=1;i<=n;i++) {
57         if( ss[l].r == i ) {
58             r = l;
59             while( r < n && ss[r+1].r == i ) ++r;
60             for(int k=l;k<=r;k++) f[i] = ( f[i] + ( sum[i-1] - sum[ss[k].l-2] ) * pows[r-k] % mod ) % mod;
61             l = r + 1;
62         }
63         sum[i] = ( sum[i-1] + f[i] ) % mod;
64     }
65     printf("%lld
",(f[n]+mod)%mod);
66     return 0;
67 }
View Code


T2:

有一个奇怪的条件:存在药和药材的完美匹配。
这是什么意思呢?就是当我们选择某种药的时候,必须选择其药材匹配的所有药。
为什么呢?考虑当前你选出的集合,每个都匹配一种药材。如果你没有选择某个没有被匹配的药材对应的药,则这些药包含的药材多一种,不符合条件。
所以一个二分图+一个最大权闭合子图就完了。

考场AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 const int maxn=3e2+1e1,maxe=maxn*maxn;
  8 const int inf = 0x3f3f3f3f;
  9 
 10 int val[maxn],n,st,ed,ans;
 11 
 12 namespace Bingraph {
 13     int in[maxn][maxn],fa[maxn];
 14     bool vis[maxn];
 15     
 16     inline bool dfs(int pos) { // pos is left point which has value .
 17         for(int i=1;i<=n;i++) if( in[pos][i] && !vis[i] ) {
 18             vis[i] = 1;
 19             if( !fa[i] || dfs(fa[i]) ) {
 20                 fa[i] = pos;
 21                 return 1;
 22             }
 23         }
 24         return 0;
 25     }
 26     inline void pir() {
 27         for(int i=1;i<=n;i++) {
 28             memset(vis,0,sizeof(vis));
 29             dfs(i);
 30         }
 31     }
 32 }
 33 
 34 namespace Flow {
 35     int s[maxn],t[maxe<<2],nxt[maxe<<2],f[maxe<<2],dep[maxn];
 36     
 37     inline void coredge(int from,int to,int flow) {
 38         static int cnt = 1;
 39         t[++cnt] = to , f[cnt] = flow ,
 40         nxt[cnt] = s[from] , s[from] = cnt;
 41     }
 42     inline void singledge(int from,int to,int flow) {
 43         coredge(from,to,flow) , coredge(to,from,0);
 44     }
 45     inline bool bfs() {
 46         memset(dep,-1,sizeof(dep)) , dep[st] = 0;
 47         queue<int> q; q.push(st);
 48         while( q.size() ) {
 49             const int pos = q.front(); q.pop();
 50             for(int at=s[pos];at;at=nxt[at])
 51                 if( f[at] && !~dep[t[at]] )
 52                     dep[t[at]] = dep[pos] + 1 , q.push(t[at]);
 53         }
 54         return ~dep[ed];
 55     }
 56     inline int dfs(int pos,int flow) {
 57         if( pos == ed ) return flow;
 58         int ret = 0 , now = 0;
 59         for(int at=s[pos];at;at=nxt[at])
 60             if( f[at] && dep[t[at]] > dep[pos] ) {
 61                 now = dfs(t[at],min(flow,f[at]));
 62                 ret += now , flow -= now ,
 63                 f[at] -= now , f[at^1] += now;
 64                 if( !flow ) return ret;
 65             }
 66         if( !ret ) dep[pos] = -1;
 67         return ret;
 68     }
 69     inline int dinic() {
 70         int ret = 0 , now = 0;
 71         while( bfs() ) {
 72             while( now = dfs(st,inf) ) ret += now;
 73         }
 74         return ret;
 75     }
 76 }
 77 
 78 inline void build() {
 79     using namespace Flow;
 80     using namespace Bingraph;
 81     st = n + 1 , ed = st + 1;
 82     for(int i=1;i<=n;i++) val[i] = -val[i];
 83     for(int i=1;i<=n;i++) {
 84         if( val[i] > 0 ) {
 85             ans += val[i];
 86             singledge(st,i,val[i]);
 87         } else singledge(i,ed,-val[i]);
 88     }
 89     for(int i=1;i<=n;i++)
 90         for(int j=1;j<=n;j++)
 91             if( in[i][j] ) {
 92                 singledge(i,fa[j],inf);
 93             }
 94 }
 95 
 96 int main() {
 97     scanf("%d",&n);
 98     for(int i=1,t,x;i<=n;i++) {
 99         scanf("%d",&t);
100         while( t-- ) {
101             scanf("%d",&x);
102             Bingraph::in[i][x] = 1;
103         }
104     }
105     for(int i=1;i<=n;i++) scanf("%d",val+i);
106     Bingraph::pir();
107     build();
108     ans -= Flow::dinic();
109     printf("%d
",-ans);
110     return 0;
111 }
View Code


T3:

看到n=1k换模数,直接就想NTT卷积了,然后发现不可做。
输出样例和随机数,立下flag说如果能多过一个点就女装。
然而一个点也没有多过。看来是天不让我女装(我也没办法是吧)。(不)
我们枚举层数为奇数的点,考虑层数为奇数的点和层数为偶数的点构成一个二分图,然后这个二分图间可以随意连边,求这个完全二分图的生成树个数。
这不是"BZOJ4766: 文艺计算姬"吗?直接n^(m-1)*m^(n-1)就好。
证明可以用prufer序列证明,n左边点出现m-1次,m个右边点出现n-1次,乘法原理即可。
别忘了因为我们钦定1号点为根,所以组合数是C(n-1,k-1)。

考场5分代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 
 4 int main() {
 5     int n,k;
 6     scanf("%d%d",&n,&k);
 7     if( n == 4 && k == 2 ) puts("12");
 8     else {
 9         srand((unsigned long long)new char);
10         printf("%d
",rand()%(n*n)+1);
11     }
12     return 0;
13 }
View Code

考后AC代码:

 1 #include<cstdio>
 2 #define lli long long int
 3 
 4 lli n,k,mod,ans;
 5 
 6 inline lli fastpow(lli base,lli tim,lli mod) {
 7     lli now = base % mod , ret = 1;
 8     while( tim ) {
 9         if ( tim & 1 ) ret = ret * now % mod;
10         if( tim >>= 1 ) now = now * now % mod;
11     }
12     return ret % mod;
13 }
14 inline lli c(lli n,lli m) {
15     lli inv = 1 , ret = 1;
16     for(lli i=n;i>n-m;i--) ret = ret * i % mod;
17     for(lli i=1;i<=m;i++) inv = inv * i % mod;
18     return ret * fastpow(inv,mod-2,mod) % mod;
19 }
20 
21 int main() {
22     scanf("%lld%lld%lld",&n,&k,&mod);
23     ans = c(n-1,k-1) * fastpow(n-k,k-1,mod) % mod * fastpow(k,n-k-1,mod) % mod;
24     printf("%lld
",ans);
25     return 0;
26 }
View Code



这次考试两个智商题一个不会,外加暴力写挂简直,果然还是我太弱了啊。
真·爆零蒟蒻XZY

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