题意:给出一个关于参数m矩阵构造方法,矩阵构造出来为(m+1)*(m+1)的,且都为0或1,给出n和t,问1<=m<=n为参数的矩阵中,最后一行的sum恰好为t的数量。
范围:n,t小于10的12次
解法:
首先根据题目给出的构造方法打表,发现前62个数满足:
1 2
1 2 2 4
1 2 2 4 2 4 4 8
1 2 2 4 2 4 4 8 2 4 4 8 4 8 8 16
1 2 2 4 2 4 4 8 2 4 4 8 4 8 8 16 2 4 4 8 4 8 8 16 4 8 8 16 8 16 16 32
很明显,是有规律的,每一行都是上一行+上一行每个数*2放到行末。
然后很有趣的是,还有进一步的规律,如果你仔细观察某一行i,对于2的j次这个值出现的次数为 C[i][j],C是组合数。
那么就简单了,因为10的12次是2的40次,一开始预处理出C数组,并计算得到n所在层数,记为I,那么前I-1行的答案直接累加就好了,最后一行则可递归求解。
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<iostream> #include<stdlib.h> #include<set> #include<map> #include<queue> #include<vector> #include<bitset> #pragma comment(linker, "/STACK:1024000000,1024000000") template <class T> bool scanff(T &ret){ //Faster Input char c; int sgn; T bit=0.1; if(c=getchar(),c==EOF) return 0; while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); if(c==' '||c=='\n'){ ret*=sgn; return 1; } while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10; ret*=sgn; return 1; } #define inf 1073741823 #define llinf 4611686018427387903LL #define PI acos(-1.0) #define lth (th<<1) #define rth (th<<1|1) #define rep(i,a,b) for(int i=int(a);i<=int(b);i++) #define drep(i,a,b) for(int i=int(a);i>=int(b);i--) #define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next) #define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++) #define mem(x,val) memset(x,val,sizeof(x)) #define mkp(a,b) make_pair(a,b) #define findx(x) lower_bound(b+1,b+1+bn,x)-b #define pb(x) push_back(x) using namespace std; typedef long long ll; typedef pair<int,int> pii; /************************************ orz学习计划: STATE: treap、splay -ing 替罪羊树 -wait 树链剖分 主席树 树套树 可持久化数据结构(论文) LC(论文) K-d Tree ------------------------------------ orz待切水题 Descripe 火柴盒 -DP HDU 4027 boring class -树套树 digger -线段树 HDU 5485 -树链剖分 Best Solver -打表题 Couple Trees -树链剖分+主席树 动态第K大 -主席树,树套树 1号大补丸 -好多题 *************************************/ ll c[55][55]; void init(){ rep(i,0,50)c[i][0]=1; rep(i,1,50) rep(j,1,50){ c[i][j]=c[i-1][j]+c[i-1][j-1]; } } ll getnum(ll pos,ll len,int n,int cot){ if(cot<0||cot>n)return 0; if(len==1)return 1; if(pos>len/2) return c[n-1][cot]+getnum(pos-len/2,len/2,n-1,cot-1); else return getnum(pos,len/2,n-1,cot); } int main(){ init(); ll m,t; scanff(m);scanff(t); ll x=1; int cot=0; while(x<t){ x<<=1; cot++; } if(x!=t){ printf("0\n"); return 0; } ll ans=0; x=2; ll y=0; int n=0; while(y<m){ y+=x; x<<=1; n++; } rep(i,max(cot,1),n-1)ans+=c[i][cot]; ans+=getnum(m-(y-x/2),x/2,n,cot); printf("%lld\n",ans); return 0; }