20180516小测

Posted Cmd2001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20180516小测相关的知识,希望对你有一定的参考价值。


T1:


我们能够证明(显然)这样的一个网络能输出任何[0,2^n-1]的排列(可以用归纳法证明),于是-1是不存在的了。
考虑每个节点只有两种状态,能否2-sat做呢?似乎有一些节点的状态是存在依赖关系的,然而并不会建图。
(于是我就写了20分暴力,先枚举那些节点激活然后进行大模拟)
正解是考虑这个网络的形态,观察可得一个节点输出的两个信号会被分配到左右的两个子网络中。
如果我们想构造出解的话,需要让第一次每个节点的两个信号进入两个不同的子网络,最后一层每个节点的两个信号从两个不同的子网络中得来。这个就是依赖关系了。
等等,这个似乎不需要2-sat,因为要字典序最小,我们能钦定第一行第一个节点状态为0,然后通过数值关系推出每个数字必须在哪个子网络中,这样与1号节点存在依赖关系的节点的状态也就都确定了。
然后继续扫描第一行,如果存在某个节点的状态没有被确定,那么让他为0与前面最优化的答案一定不冲突,我们就让他为0,然后继续递推就好了。
然后完成某一级的答案求解后,递归求出两个子网络的状态即可。
复杂度O(n*2^n)。

20分暴力代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 const int maxn=11;
 4 const int inf=0x3f3f3f3f;
 5 
 6 bool sta[maxn][maxn];
 7 int in[maxn][maxn],tar[maxn],Log[maxn];
 8 
 9 inline int shl(int x,int l) {
10     int ret = 0;
11     for(int i=0;i<l;i++) if( x & ( 1 << i ) ) ret |= 1 << ( ( i - 1 + l ) % l );
12     return ret;
13 }
14 inline int shr(int x,int l) {
15     int ret = 0;
16     for(int i=0;i<l;i++) if( x & ( 1 << i ) ) ret |= 1 << ( ( i + 1 ) % l );
17     return ret;
18 }
19 
20 inline void solve(int x,int y,int z,int inlev,int outlev,int n) { // doubled data level .
21     if( n == 1 ) return;
22     for(int i=0;i<n>>1;i++) { // cross node from inlev to inlev + 1 .
23         int l = y + i * 2 , r = y + i * 2 + 1;
24         in[inlev+1][l] = in[inlev][l] , in[inlev+1][r] = in[inlev][r];
25         if( sta[x][(y>>1)+i] ) std::swap(in[inlev+1][l],in[inlev+1][r]);
26     }
27     if( n != 2 ) {
28         for(int i=0;i<n>>1;i++) { // cross line from inlev + 1 to inlev + 2 .
29             int ix = y + i * 2 , iy = y + i * 2 + 1 , ox = y + shl(i*2,Log[n]) , oy = y + shl(i*2+1,Log[n]);
30             in[inlev+2][ox] = in[inlev+1][ix] , in[inlev+2][oy] = in[inlev+1][iy];
31         }
32         solve(x+1,y,z-1,inlev+2,outlev-2,n>>1) , solve(x+1,y+(n>>1),z-1,inlev+2,outlev-2,n>>1);
33         for(int i=0;i<n>>1;i++) { // cross line from outlev - 1 to outlev .
34             int ix = y + i * 2 , iy = y + i * 2 + 1 , ox = y + shr(i*2,Log[n]) , oy = y + shr(i*2+1,Log[n]);
35             in[outlev][ox] = in[outlev-1][ix] , in[outlev][oy] = in[outlev-1][iy];
36         }
37     }
38     for(int i=0;i<n>>1;i++) { // cross node from outlev to outlev + 1.
39         int l = y + i * 2 , r = y + i * 2 + 1;
40         in[outlev+1][l] = in[outlev][l] , in[outlev+1][r] = in[outlev][r];
41         if( sta[z][(y>>1)+i] ) std::swap(in[outlev+1][l],in[outlev+1][r]);
42     }
43 }
44 
45 inline bool dif(int n,int n_lev) {
46     for(int i=0;i<1<<n;i++) if( in[n_lev][i] != tar[i] ) return 1;
47     return 0;
48 }
49 inline void unzipsta(int ss,int x,int y) {
50     for(int i=x-1;~i;i--) for(int j=y-1;~j;j--) sta[i][j] = ss & 1 , ss >>= 1;
51 }
52 
53 int main()
54     static int sol,n,full,n_nod,m_nod,n_lev;
55     while( scanf("%d",&n) == 1 && n ) {
56         sol = 0 , n_nod = 2 * n - 1 , m_nod = 1 << ( n - 1 ) , n_lev = 2 * n_nod - 1 , full = 1 << ( n_nod * m_nod );
57         for(int i=0;i<=n;i++) Log[1<<i] = i;
58         for(int i=0;i<1<<n;i++) scanf("%d",tar+i);
59         for(int i=0;i<full&&!sol;i++) {
60             for(int j=0;j<1<<n;j++) in[0][j] = j;
61             unzipsta(i,n_nod,m_nod) , solve(0,0,n_nod-1,0,n_lev-1,1<<n);
62             if( !dif(n,n_lev) ) sol = 1;
63         }
64         if( !sol ) puts("-1");
65         else {
66             for(int i=0;i<n_nod;i++) {
67                 for(int j=0;j<m_nod;j++) putchar(\'0\'+sta[i][j]);
68                 putchar(\'\\n\');
69             }
70         }
71         putchar(\'\\n\');
72     }
73     return 0;
74 }
View Code

正解代码:
(原谅我代码写得像天书一样)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define debug cout
using namespace std;
const int maxe=30,maxn=1<<14;

bool ans[maxe][maxn];
int in[maxe][maxn],Log[maxn];
int lim[maxn],app[maxn],rapp[maxn];
int n,nod_n,nod_m,data_m;

inline int shl(int x,int l) { // looping bit left move .
    int ret = 0;
    for(int i=0;i<l;i++) if( x & ( 1 << i ) ) ret |= 1 << ( ( i - 1 + l ) % l );
    return ret;
}
inline int shr(int x,int l) { // looping bit right move .
    int ret = 0;
    for(int i=0;i<l;i++) if( x & ( 1 << i ) ) ret |= 1 << ( ( i + 1 ) % l );
    return ret;
}

inline void dfs(int inlev,int outlev,int cur,int pos) { // cur = 0 or 1 means up or down .
    int oth = pos ^ 1;
    if( !cur ) { // solve by inklev .
        if( !~lim[in[inlev][oth]] ) lim[in[inlev][oth]] = lim[in[inlev][pos]] ^ 1 , dfs(inlev,outlev,0,oth);
        int op = app[in[inlev][pos]] , oop = op ^ 1;
        if( !~lim[in[outlev][oop]] ) lim[in[outlev][oop]] = lim[in[outlev][op]] ^ 1 , dfs(inlev,outlev,1,oop);
    } else {
        if( !~lim[in[outlev][oth]] ) lim[in[outlev][oth]] = lim[in[outlev][pos]] ^ 1 , dfs(inlev,outlev,1,oth);
        int op = rapp[in[outlev][pos]] , oop = op ^ 1;
        if( !~lim[in[inlev][oop]] ) lim[in[inlev][oop]] = lim[in[inlev][op]] ^ 1 , dfs(inlev,outlev,0,oop);
    }
}
inline void solve(int sx,int sy,int tx,int inlev,int outlev,int n) { // n is count of points , n >> 1 is count of nodes , sx and sy are position of nodes .
    if( n == 2 ) {
        if( in[inlev][sy<<1] != in[outlev][sy<<1] ) ans[sx][sy] = 1;
        return;
    }
    
    for(int i=0;i<n;i++) lim[in[inlev][(sy<<1)+i]] = -1;
    for(int i=0;i<n;i++) app[in[outlev][(sy<<1)+i]] = (sy<<1)+i , rapp[in[inlev][(sy<<1)+i]] = (sy<<1)+i;
    const int mid = ( sy << 1 ) + ( n >> 1 ) - 1;
    
    for(int i=0;i<n>>1;i++) {
        int l = (sy<<1) + (i<<1) , r = (sy<<1) + (i<<1|1) , tl = (sy<<1) + shl(i<<1,Log[n]) , tr = (sy<<1) + shl(i<<1|1,Log[n]);
        if( !~lim[in[inlev][l]] && !~lim[in[inlev][r]] ) lim[in[inlev][l]] = tl > mid , lim[in[inlev][r]] = tr > mid; // left 0 , right 1 .
        else { // solve limit .
            if( ~lim[in[inlev][l]] ) lim[in[inlev][r]] = lim[in[inlev][l]] ^ 1;
            else lim[in[inlev][l]] = lim[in[inlev][r]] ^ 1;
            ans[sx][sy+i] = ( tl > mid ) ^ lim[in[inlev][l]];
        }
        dfs(inlev,outlev,0,l) , dfs(inlev,outlev,0,r);
        
        int pl = app[in[inlev][l]] , bpl = ( pl - (sy<<1) ) >> 1 , bpl_l = (sy<<1) + (bpl<<1) , bpl_l_tarsou = (sy<<1) + shl(bpl<<1,Log[n]);
        ans[tx][sy+bpl] = ( bpl_l_tarsou > mid ) ^ lim[in[outlev][bpl_l]];
        
        int pr = app[in[inlev][r]] , bpr = ( pr - (sy<<1) ) >> 1 , bpr_l = (sy<<1) + (bpr<<1) , bpr_l_tarsou = (sy<<1) + shl(bpr<<1,Log[n]);
        ans[tx][sy+bpr] = ( bpr_l_tarsou > mid ) ^ lim[in[outlev][bpr_l]];
        
    }
    
    for(int i=0;i<n>>1;i++) { // trans data to next level .
        int l = (sy<<1) + (i<<1) , r = (sy<<1) + (i<<1|1) , tl = (sy<<1) + shl(i<<1,Log[n]) , tr = (sy<<1) + shl(i<<1|1,Log[n]);
        in[inlev+1][tl] = in[inlev][l] , in[inlev+1][tr] = in[inlev][r];
        if(ans[sx][sy+i]) swap(in[inlev+1][tl],in[inlev+1][tr]);
    }
    for(int i=0;i<n>>1;i++) { // trans data to previous level .
        int l = (sy<<1) + (i<<1) , r = (sy<<1) + (i<<1|1) , fl = (sy<<1) + shl(i<<1,Log[n]) , fr = (sy<<1) + shl(i<<1|1,Log[n]);
        in[outlev-1][fl] = in[outlev][l] , in[outlev-1][fr] = in[outlev][r];
        if(ans[tx][sy+i]) swap(in[outlev-1][fl],in[outlev-1][fr]);
    }
    
    solve(sx+1,sy,tx-1,inlev+1,outlev-1,n>>1) , solve(sx+1,sy+(n>>2),tx-1,inlev+1,outlev-1,n>>1);
}

inline void reset() {
    memset(ans,0,sizeof(ans));
}

int main() {
    while( scanf("%d",&n) == 1 && n ) {
        reset() , nod_n = ( n << 1 ) - 1 , nod_m = 1 << ( n - 1 ) , data_m = 1 << n;
        for(int i=0;i<=n;i++) Log[1<<i] = i;
        for(int i=0;i<data_m;i++) in[0][i] = i , scanf("%d",in[nod_n]+i);
        solve(0,0,nod_n-1,0,nod_n,data_m);
        for(int i=0;i<nod_n;i++) {
            for(int j=0;j<nod_m;j++) putchar(\'0\'+ans[i][j]);
            putchar(\'\\n\');
        }
        putchar(\'\\n\');
    }
    return 0;
}
View Code

 


T2:

观察这个生成的序列,发现没什么性质(没错,它最大的性质就是随机!)。
于是没什么好办法,只好用数据结构做了。
平衡树和线段树是不用想了,铁定TLE(线段树还会MLE),我们需要一个更优美的做法。
用堆!一个大根堆维护序列的前半部分,一个小根堆维护序列的后半部分。
每次把新生成的数插入前半部分的大根堆,当这个堆的大小比(i+1)/2大时,弹出堆顶并把堆顶放进后半部分的小根堆。
如果当前大根堆堆顶比小根堆堆顶大的话,我们就交换这两个堆顶的元素(两个push两个pop)。
显然对于插入的每个数字,第一种操作只会进行1次,对于每一个i,第二种操作只会进行O(1)次,总复杂度O(nlogn)。
很不幸的是,这样做也只有50分,即使你用pb_ds的配对堆或斐波那契堆。
考虑复杂度瓶颈在哪里,我们每次对堆进行操作的时候,都要承受一个巨大的log。
好的,我们还是维护两个堆,在中间维护一棵平衡树作为缓存,保证当前查询的那个数值永远在平衡树里。用这棵平衡树减少堆的操作并限制它的大小来减小log,是不是就能卡过去了呢?
具体操作就是,插入的时候判断新加的值在那一段,加入正确的位置;
当平衡树的大小和第一个堆大小的和比当前要查询的数值小时,从第二个堆中取出数字放进平衡树中;
当平衡树的大小比阈值大时,把平衡树开始或结尾的元素移动到大小较小的那个堆中。
因为数据随机,所以如果平衡树缓存大小合适,我们对两边的堆的操作会大幅度减少,于是就可以AC了。

50分暴力代码:

 1 #pragma GCC optimize("Ofast")
 2 #pragma GCC target("avx")
 3 #pragma GCC optimize("no-stack-protector")
 4 #include<cstdio>
 5 #include<ext/pb_ds/priority_queue.hpp>
 6 #define ull unsigned long long
 7 using namespace std;
 8 using namespace __gnu_pbds;
 9 const unsigned mod=1e9+7;
10  
11 __gnu_pbds::priority_queue<unsigned,less<unsigned>,binary_heap_tag> exs;
12 __gnu_pbds::priority_queue<unsigned,greater<unsigned>,binary_heap_tag> del;
13 
14 __inline unsigned gen(const unsigned &t,const unsigned &ans) {
15     return ( 714636908ull * t % mod + 681692770u ) * ( 846930886ull * ans % mod + 804289376u ) % mod;
16 }
17 
18 int main() {
19     static unsigned n,t,ans,out;
20     scanf("%u%u",&n,&t);
21     for(register unsigned i=1,p=1;i<=n;i++,p=(i+1)>>1) {
22         exs.push(t);
23         while( exs.size() > p ) del.push(exs.top()) , exs.pop();
24         while( del.size() && del.top() < exs.top() ) exs.push(del.top()) , del.pop() , del.push(exs.top()) , exs.pop();
25         ans = exs.top() , out ^= ans , t = gen(t,ans);
26     }
27     printf("%u\\n",out);
28     return 0;
29 }
View Code

正解代码:

 1 /*#pragma GCC optimize("Ofast")
 2 #pragma GCC target("avx")
 3 #pragma GCC optimize("no-stack-protector")*/
 4 #include<cstdio>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 #include<ext/pb_ds/tree_policy.hpp>
 9 #include<ext/pb_ds/assoc_container.hpp>
10 typedef unsigned long long int ulli;
11 const int mod=1e9+7;
12 const int lim=10;
13 
14 std::priority_queue<ulli,std::vector<ulli>,std::less<ulli> > lft;
15 std::priority_queue<ulli,std::vector<ulli>,std::greater<ulli> > rit;
16 __gnu_pbds::tree<ulli,__gnu_pbds::null_type,std::less<ulli>,__gnu_pbds::rb_tree_tag,__gnu_pbds::tree_order_statistics_node_update> buf;
17 
18 __inline unsigned gen(const unsigned &t,const unsigned &ans) {
19     return ( 714636908ull * t % mod + 681692770u ) * ( 846930886ull * ans % mod + 804289376u ) % mod;
20 }
21 
22 int main() {
23     static unsigned n,t,ans,out;
24     scanf("%u%u",&n,&t);
25     for(register unsigned i=1,p;i<=n;i++) {
26         p = ( i + 1 ) >> 1;
27         register ulli cur = (ulli) t * ( mod + 1 ) + i;
28         if( buf.size() && cur < *buf.begin() ) lft.push(cur);
29         else if( buf.size() && cur > *buf.rbegin() ) rit.push(cur);
30         else buf.insert(cur);
31         while( p > lft.size() + buf.size() ) buf.insert(rit.top()) , rit.pop();
32         while( p <= lft.size() ) buf.insert(lft.top()) , lft.pop();
33         out ^= ans = *buf.find_by_order(p-lft.size()-1) / ( mod + 1 ) ;
34         t = gen(t,ans);
35         while( buf.size() > lim ) {
36             if( lft.size() < rit.size() ) lft.push(*buf.begin()) , buf.erase(buf.begin());
37             else rit.push(*buf.rbegin()) , buf.erase(buf.rbegin());
38         }
39     }
40     printf("%u\\n",out);
41     return 0;
42 }
View Code

 


T3:


博弈论+数据结构?
SG函数怎么推啊......只知道P为奇数时,SG值为当前元素的奇偶性。数据不保证P的奇偶,写了也不一定有分,弃疗了。
假设我们打表观察(出题人写的)这个题的SG函数是这样的:
当P为奇数时,大小为n的堆的SG值为 n mod 2。
当P为偶数时,大小为n的堆的SG值为:
如果 n mod P + 1 = P , 则为2;
否则为 n mod P + 1 mod 2。
考虑怎么证明。
P为奇数时的SG值显然,因为每次操作一定改变堆大小的奇偶性。
P为偶数时的证明就比较麻烦了......
因为a^2-1=(a+1)*(a-1),故 a^2-1+1=(a+1)*(a-1)+1 = 1 mod a+1 , 所以 a^3 = a * a^2 = a mod a+1。
所以,取p^k的情况,在mod p+1下都能划归为取1或者取p的情况。
所以我们可以在P+1的同余系下做。如果 mod P+1 < P 的话,只能取1,所以SG值为 n mod P + 1 mod 2 。
而mod P+1 = P的情况,我们可以取p,到SG值为0的状态0和SG值为1的状态P-1,故这个状态的SG值为mex(1,2)=2。

于是我们对于P为奇数和偶数的情况分别计算。
P为奇数的话,相当于区间 xor 1,求区间 xor 和,线段树轻松搞定。
P为偶数的情况,我们需要分块。
考虑我们先让所有数值mod P+1再按照mod 2将这些数值放入两个有序数组里。
那么,如果区间同时加上add,所有>=P+1-add的数会溢出一轮。
如果add为偶数的话,溢出的数的奇偶性改变,没溢出的数的奇偶性不变;
如果add为奇数的话,溢出的数的奇偶性不变,没溢出的数的奇偶性改变。
这样我们维护两个有序数组每次lower_bound一下就好了,当然如果你非得写平衡树也没人拦你。
(什么?mod P+1 = P的?满足这种情况的只有一个数就是P+1-add,我们用一个map存mod P+1为某个数的值有多少个,再手动从奇偶两种减去这个值的贡献就好了)

代码:

  1 #pragma GCC optimize("Ofast")
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<map>
  5 #include<vector>
  6 #include<cmath>
  7 const int maxn=1e5+1e2,maxe=325;
  8 
  9 int n,m,a;
 10 
 11 namespace Even {
 12     int dat[maxn],bel[maxn],st[maxe],ed[maxe],add[maxe];
 13     std::vector<int> cont[maxe][2];
 14     std::map<int,

以上是关于20180516小测的主要内容,如果未能解决你的问题,请参考以下文章

Java小测代码及截图

php 20180516 hoverをjQで制御

20180516早课记录11-Linux

javascript 20180516谷歌地图をレスポンシブ対にに

php 20180516タブ切り替え内のマッチハイト

20180630小测