话说咱也不知道自己为啥这么菜,1900分的dp要写半天。。但是这个题的思想很关键,还有就是那个欧拉定理,n^k %p 等同于n^(k%(p-1))%p。
题意是给你一个n*m的矩阵,让你往里面填数,没n*n个格子里面恰好有k个的方案数,n<=100,n*m<=1e18,k<=n*n;感觉好像很像个状压一样,不过n的范围就不行了,所以考虑计数dp,这题的关键在于,如果存在一种合法的方案,则对于m%n的这一系的列中,他们的数量都是一样的。所以相同的这些列计算起来即为次方数,但别忘了次方处理要用欧拉定理%(mod-1)。然后就是dp了,dp[i][j]代表前i行选j个的合法方案数,(j<=i*n).状态转移显然:dp[i][j]=dp[i-1][j-p](前面选j-p个)*c[n][p]^cnt[i](这一列选p个)。注意状态顺序不要写成n*k*k的 因为第三层我们只需枚举到(1-n)所以是n*k*n的,复杂度为n的四次方+n方log(1e9+7)
Table
time limit per test
4 seconds
memory limit per test
256 megabytes
John Doe has an n × m table. John Doe can paint points in some table cells, not more than one point in one table cell. John Doe wants to use such operations to make each square subtable of size n × n have exactly k points.
John Doe wondered, how many distinct ways to fill the table with points are there, provided that the condition must hold. As this number can be rather large, John Doe asks to find its remainder after dividing by 1000000007 (109 + 7).
You should assume that John always paints a point exactly in the center of some cell. Two ways to fill a table are considered distinct, if there exists a table cell, that has a point in one way and doesn't have it in the other.
Input
A single line contains space-separated integers n, m, k (1 ≤ n ≤ 100; n ≤ m ≤ 1018; 0 ≤ k ≤ n2) — the number of rows of the table, the number of columns of the table and the number of points each square must contain.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
Output
In a single line print a single integer — the remainder from dividing the described number of ways by 1000000007 (109 + 7).
Examples
input
Copy
5 6 1
output
Copy
45
Note
Let's consider the first test case:
The gray area belongs to both 5 × 5 squares. So, if it has one point, then there shouldn't be points in any other place. If one of the white areas has a point, then the other one also must have a point. Thus, there are about 20 variants, where the point lies in the gray area and 25 variants, where each of the white areas contains a point. Overall there are 45 variants.
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
typedef long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
typedef unsigned long long ull;
typedef unsigned short us;
const ll INF= 1e18+7;
const ll maxx = 2e5+7;
const ll mod= 1e9+7;
const double eps=1e-8;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,k;
ll l[maxx],r[maxx];
ll dp[120][12000];// i,j 前i行选j个
ll cnt[120]; // num个数
ll c[120][120]; // 组合数
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) {
ans=ans*a%mod;
}
b>>=1;
a=a*a%mod;
}
return ans;
}
int main()
{
ll t;
ll ans=0;
c[0][0]=1;
c[1][0]=1;
c[1][1]=1;
rep(i,2,110)
{
rep(j,0,i)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j]) %mod;
}
}
//rep(i,0,110) dp[0][i]=1;
rep(i,0,110) c[i][0]=1;
cin>>n>>m>>k;
ll p=m%n;
ll num=m/n;
rep(i,1,n)
{
cnt[i]=num;
if(p>=i) cnt[i]++;
cnt[i]%=(mod-1);//
}
rep(i,0,110) dp[i][0]=1;
rep(i,1,n)
{
ll num=min(n,k);
for(ll p=0;p<=num;p++)
{
//printf("%lld %lld\n",n,p);
ll x=qpow(c[n][p],cnt[i]);
rep(j,p,k)
{
if(j==0) continue;
dp[i][j]=( dp[i][j]+ (dp[i-1][j-p]*x) %mod) %mod;
}
}
}
printf("%lld\n",(mod+dp[n][k]) %mod );
return 0;
}
/*
80 500000000000000000 3200
*/