网站被百度蜘蛛爬了多久放出来,网站建设 源码,做外围网站犯法吗,佛山做优化的公司problem
题目链接
solution
从最小一个数 xxx 开始#xff0c;将其 2x,3x2x,3x2x,3x 放入#xff0c;再将 2(2x),3(2x),2(3x),3(3x)2(2x),3(2x),2(3x),3(3x)2(2x),3(2x),2(3x),3(3x) 放入#xff0c;以此类推 …\dots… 将其合并为一个集合。重复又找一个最小未进入集合的…problem
题目链接
solution
从最小一个数 xxx 开始将其 2x,3x2x,3x2x,3x 放入再将 2(2x),3(2x),2(3x),3(3x)2(2x),3(2x),2(3x),3(3x)2(2x),3(2x),2(3x),3(3x) 放入以此类推 …\dots… 将其合并为一个集合。重复又找一个最小未进入集合的数 xxx。
显然答案为若干个互不相交并集为 [1,n][1,n][1,n] 的集合答案的乘积。
一个集合里面的数字是相互制约的不难发现集合大小不超过 log2n∗log3n\log_2n*\log_3nlog2n∗log3n大概就是 17×1117\times 1117×11。
考虑怎么计算一个独立集合的可选方案数。
很巧妙的是这个限制只有两个两倍和三倍在平面内可以构造出一个矩阵。
矩阵中 (i,j)(i,j)(i,j) 的右边位置放其数值的三倍下面位置放其数值的两倍。
1 3 9 ...
2 6 18 ...
4 12 36 ...
那么答案就等价为在矩阵中随机选任意个数要求数两两不相邻。
矩阵行列数都比较小可以采取状压 dpdpdp 求解。
显然某一行是否合法与矩阵真实长相无关至于选择的位置有关。
所以提前预处理一行的选择状态判断是否合法。不合法当且仅当有相邻两列都选了用 i1i 判断。
之后枚举当前行及操作状态在合法的基础上枚举上一行的操作状态再判断两行之间没有同一列都操作了用 st0 判断。
能构造矩阵完全是因为限制一个数的条件只有两个可以放在二维平面内。这完全就是很投巧的想法。
code
#include bits/stdc.h
using namespace std;
#define mod 1000000001
#define int long long
int N, n, m, ans 1;
bool vis[100005], g[1 20];
int lim[20], a[20][20], f[20][1 20];void init( int x ) {for( int i 1;;i ) {if( i 1 ) a[i][1] x;else a[i][1] a[i - 1][1] 1;if( a[i][1] N ) break;else n i;vis[a[i][1]] 1;lim[i] 2;for( int j 2;;j ) {a[i][j] a[i][j - 1] * 3;if( a[i][j] N ) break;else vis[a[i][j]] 1, lim[i] 1 j;}}
}int solve() {for( int i 0;i lim[1];i ) f[1][i] g[i];for( int i 2;i n;i )for( int s 0;s lim[i];s ) {if( ! g[s] ) continue;f[i][s] 0;for( int t 0;t lim[i - 1];t )if( g[t] and ! (s t) )f[i][s] ( f[i][s] f[i - 1][t] ) % mod;}int ret 0;for( int i 0;i lim[n];i )ret ( ret f[n][i] ) % mod;return ret;
}signed main() {for( int i 0;i (1 19);i )g[i] ! (i 1 i);scanf( %lld, N );for( int i 1;i N;i )if( ! vis[i] ) init( i ), ans ans * solve() % mod;printf( %lld\n, ans );return 0;
}