考虑两个数列整数列A = {a[1], a[2], …, a[n]} and B = {b[1], b[2], …, b[n]},如果从两个数列中各取一项a[i]和b[j],其和各不相同且全部在[1,n*n]内,则称(A,B)是一个数列对。求本质不同的数列对数。
如果两个数列对在进行以下操作或以下若干操作的组合后相同,那么则认为他们是本质相同的:
交换A和B;
A的每个数减一常数,B的每个数加一常数;
交换A中或B中任意两个数。
所以,你可以认为a[1]=0,b[1]=1,A,B均按升序排列。
第一行一个整数T表示测试数据个数;
以下T行每行一个整数n表示序列的长度。
对于每个测试数据输出一行,表示本质不同的数列对个数。
N=4时,本质不同的数列对有3个:
(A={0,1,2,3}, B={1,5,9,13})
(A={0,1,4,5}, B={1,3,9,11})
(A={0,1,8,9}, B={1,3,5,7})
【数据规模及约定】
对于100%的数据,n<=1000。
手算发现符合条件的数列都为
XX....XX.....XX.....XX........
假设相邻X的长度为t
于是记忆化搜索。
s=1 暴力枚举t
s=0 根据一一对应关系,转成F[H,H/n,1]
初始状态是n=1(只有一个X)
此时唯一的排法是A={1,2,3,..,h},B={0}
所以F[H,1,0]=1 F[h,1,1]=0
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> #include<map> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define ForD(i,n) for(int i=n;i;i--) #define RepD(i,n) for(int i=n;i>=0;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define MAXN (2000+10) int T,n; struct node { int h,n; bool s; node(){} node(int _h,int _n,bool _s):h(_h),n(_n),s(_s){} friend bool operator<(node a,node b){if (a.h^b.h) return a.h<b.h;if (a.n<b.n) return a.n<b.n;if (a.s<b.s) return a.s<b.s;} }; map< node ,long long> f; long long dfs(int h,int n,bool s) /*总长,取数 s=0 循环节=1;s=1 循环节>1*/ { node a=node(h,n,s); if (f.find(a)!=f.end()) return f[a]; if (!s) return f[a]=(n==1?1:dfs(h,h/n,1)); if (n==1) return f[a]=0; long long ans=0; For(t,sqrt(n)) if (n%t==0) { if (t>1) ans+=dfs(h/t,n/t,0); if (t*t<n) ans+=dfs(h/(n/t),t,0); } return f[a]=ans; } int main() { // freopen("bzoj2833.in","r",stdin); cin>>T; while (T--) { scanf("%d",&n); if (n==1) cout<<"1"<<endl; else cout<<dfs(n*n,n,1)<<endl; } return 0; }