我是靠谱客的博主 疯狂蚂蚁,最近开发中收集的这篇文章主要介绍BZOJ 2833(数列对计数-分段Dp),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2833: 数列对计数

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 19  Solved: 12
[ Submit][ Status][ Discuss]

Description

考虑两个数列整数列A = {a[1], a[2], …, a[n]} and B = {b[1], b[2], …, b[n]},如果从两个数列中各取一项a[i]b[j],其和各不相同且全部在[1,n*n]内,则称(A,B)是一个数列对。求本质不同的数列对数。

如果两个数列对在进行以下操作或以下若干操作的组合后相同,那么则认为他们是本质相同的:

交换AB

A的每个数减一常数,B的每个数加一常数;

交换A中或B中任意两个数。

所以,你可以认为a[1]=0b[1]=1A,B均按升序排列。

Input

第一行一个整数T表示测试数据个数;

以下T行每行一个整数n表示序列的长度。

Output

对于每个测试数据输出一行,表示本质不同的数列对个数。

Sample Input

4

1

2

3

4

Sample Output


1

1

1

3

HINT



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。


 

Source

手算发现符合条件的数列都为

XX....XX.....XX.....XX........

假设相邻X的长度为t


F[H,n,s]表示长度为h的区间,放n个X,其中s=0表示t=1,s=1表示t>1

于是记忆化搜索。

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;
}





最后

以上就是疯狂蚂蚁为你收集整理的BZOJ 2833(数列对计数-分段Dp)的全部内容,希望文章能够帮你解决BZOJ 2833(数列对计数-分段Dp)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部