> 文章列表 > 【学习笔记】CF1054

【学习笔记】CF1054

【学习笔记】CF1054

是我降智了。

开始在想一些抽屉原理之类的东西,发现不太行。

注意到,一个位置上的 0 , 1 0,1 0,1移到左上角或右下角最多需要两步,那么我们可以将初末状态都移成 0 0 0全部在 ( 1 , 1 ) (1,1) (1,1)上, 1 1 1全部在 ( n , n ) (n,n) (n,n)上,两部分都最多需要 2 s 2s 2s步,然后就做完了。

具体做法可以自己编,总之是有一点繁琐。

复制粘贴半天才发现我把串翻转过来就行了,我是joker

二分图,但是我没看出来。

事实上,只要第一步正确,剩下的就非常容易了:我们将初始局面看成,每一个交点处连接两条横竖线段。那么只要不产生多余的交点即可,两个交点有可能合并起来让答案减少 1 1 1。将行列离散化过后相当于 n n n个点的二分图,有 n 2 n^2 n2条边,求最大独立集,然后就做完了。

没想到可以直接在残留网络上找方案,妙啊

下次研究一下残留网络的性质

不会做,只会照搬题解。

S i S_i Si表示包含点 i i i的社区的集合。如果一个社区的大小为 1 1 1,那么显然可以直接删去;否则考虑叶子节点 x x x,设其父亲节点为 y y y,那么一个连通块如果包含 x x x,显然也会包含 y y y,也就是 S x ⊆ S y S_x\\subseteq S_y SxSy。这个限制看着非常亲切啊,因为假设我们知道了叶子节点 x x x,那么把所有社区中的 x x x删去,再将 x x x y y y连边就转化为一个子问题了。那么我们每次取出 ∣ S i ∣ |S_i| Si最小的作为 x x x,然后再找到父节点 y y y(其中 S x ⊆ S y S_x\\subseteq S_y SxSy),然后重复上述操作就做完了。

复杂度 O ( n 2 m w ) O(\\frac{n^2m}{w}) O(wn2m)

调不出来

好像要用队列写,但不知道为啥。

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int T,n,m,vis[2005],sz[2005];
bitset<2005>b[2005];
string str;
vector<pair<int,int>>edges;void solve(){edges.clear();for(int i=1;i<n;i++){int x=-1,y=-1;for(int j=0;j<n;j++){if(!vis[j]&&(x==-1||b[j].count()<b[x].count())){x=j;}}vis[x]=1;for(int j=0;j<n;j++){if(!vis[j]&&(b[j]&b[x])==b[x]){y=j;break;}}if(y==-1){cout<<"NO"<<"\\n";return;}edges.pb({x,y});for(int j=b[x]._Find_first();j!=b[x].size();j=b[x]._Find_next(j)){if(--sz[j]==1){b[y][j]=0;}}}cout<<"YES"<<"\\n";for(auto x:edges){cout<<x.fi+1<<" "<<x.se+1<<"\\n";}
}
int main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>T;while(T--){cin>>n>>m;for(int i=0;i<n;i++)b[i].reset(),vis[i]=0;for(int i=0;i<m;i++){cin>>str,sz[i]=0;for(int j=0;j<n;j++){if(str[j]=='1')sz[i]++;}if(sz[i]>1){for(int j=0;j<n;j++){if(str[j]=='1')b[j][i]=1;}}}solve();}
}

这是一道数学题。

因为 p p p是质数,根据欧拉定理,记 c k = ∑ i 2 j 3 m o d 490018 = k a i b j c_k=\\sum_{i^2j^3\\bmod 490018=k}a_ib_j ck=i2j3mod490018=kaibj,那么答案是 ∑ c k x k \\sum c_kx^k ckxk

为什么这么拆,是因为前面很像一个卷积的形式。

根据中国剩余定理,我们只需要考虑模 2 , 491 , 499 2,491,499 2,491,499的余数,其中 491 , 499 491,499 491,499都是质数因此一定有原根, 491 491 491有原根 2 2 2 499 499 499有原根 7 7 7。因此,我们取 i 2 i^2 i2, j 3 j^3 j3的离散对数(也就是原根的指数)就能把乘法转换成加法,而模 2 2 2相当于是与运算。即求 c i , j , k = ∑ i 1 and  i 2 = 1 , j 1 + j 2 = j , k 1 + k 2 = k a i 1 , j 1 , k 1 b i 2 , j 2 , k 2 c_{i,j,k}=\\sum_{i_1\\text{and }i_2=1,j_1+j_2=j,k_1+k_2=k}a_{i_1,j_1,k_1}b_{i_2,j_2,k_2} ci,j,k=i1and i2=1,j1+j2=j,k1+k2=kai1,j1,k1bi2,j2,k2。这里涉及到二维 f f t fft fft的问题,可以先按行做一遍卷积,再按列做一遍卷积, i d f t idft idft也同理。不过注意 i 2 , j 3 i^2,j^3 i2,j3 491 , 499 491,499 491,499倍数的时候 没有原根,这部分需要暴力处理。

这道题有点难写。代码先咕了。