10.19的一些题

T1 bzoj 1951 古代猪文

题目大意:

给正整数n G 求(G^sigma{C(n,n/i),i|n})%P

思路:

数论题大合集.jpg

设res=sigma{C(n,n/i),i|n 由于res可能很大

由费马小定理可得 我们只需要求res%(P-1)

快速求C需要lucas 因为P-1不是质数 所以还需要使用中国剩余定理合并

最后再快速幂即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define inf 2139062143
11 #define ll long long
12 #define MAXN 40100
13 #define MOD 999911659
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 int n,inv[4][MAXN],m[4]={2,3,4679,35617};
23 ll g[4][MAXN],bas,ans[4];
24 inline void mem()
25 {
26     for(int k=0;k<4;k++)
27     {
28         inv[k][0]=inv[k][1]=g[k][0]=g[k][1]=1;
29         for(int i=2;i<m[k];i++) inv[k][i]=(m[k]-m[k]/i)*inv[k][m[k]%i]%m[k],g[k][i]=(g[k][i-1]*i)%m[k];
30         for(int i=2;i<m[k];i++) (inv[k][i]*=inv[k][i-1])%=m[k];
31         //cout<<k<<" "<<ans[0]<<" "<<ans[1]<<" "<<ans[2]<<" "<<ans[3]<<endl;
32         //cout<<inv[k][2]<<endl;
33     }
34     //cout<<ans[0]<<" "<<ans[1]<<" "<<ans[2]<<" "<<ans[3]<<endl;
35 }
36 inline ll C(ll n,ll x,int k)
37 {
38     //cout<<"C: "<<n<<" "<<x<<" "<<k<<" "<<g[k][n]<<" "<<inv[k][x]<<" "<<inv[k][n-x]<<endl;
39     if(n<x) return 0LL;
40     return (g[k][n]*inv[k][x]*inv[k][n-x])%m[k];
41 }
42 ll lucas(ll n,ll x,int k)
43 {
44     //cout<<"L: "<<n<<" "<<x<<" "<<k<<" "<<g[k][n]<<" "<<inv[k][x]<<" "<<inv[k][n-x]<<endl;
45     if(!x) return 1LL;
46     return (lucas(n/m[k],x/m[k],k)*C(n%m[k],x%m[k],k))%m[k];
47     //return *C(n%m[x],x%m[x],k))%m[x];
48 }
49 inline void work(int x)
50 {
51     for(int i=0;i<4;i++){
52         //cout<<x<<" "<<i<<" "<<ans[0]<<" "<<ans[1]<<" "<<ans[2]<<" "<<ans[3]<<endl;
53         (ans[i]+=lucas(n,x,i))%=m[i];
54     }
55         //cout<<x<<" "<<ans[0]<<" "<<ans[1]<<" "<<ans[2]<<" "<<ans[3]<<endl;
56 }
57 inline ll exgcd(ll a,ll b,ll &x,ll &y)
58 {
59     if(!b) {x=1,y=0;return a;}
60     ll d=exgcd(b,a%b,y,x);y-=(a/b)*x;return d;
61 }
62 inline ll q_pow(ll t)
63 {
64     //cout<<t<<endl;
65     ll res=1;
66     for(;t;t>>=1,(bas*=bas)%=MOD)
67     {
68         //cout<<t<<" "<<res<<" "<<bas<<endl;
69         if(t&1) (res*=bas)%=MOD;
70     }
71     return (res+MOD)%MOD;
72 }
73 int main()
74 {
75     n=read(),bas=read();mem();
76     if(bas==MOD) {puts("0");return 0;}
77     for(int i=1;i*i<=n;i++)
78         if(n%i==0) {work(i);if(i*i!=n) work(n/i);}
79     ll x,y,s=MOD-1,res=0;
80     for(int i=0;i<4;i++)
81     {
82         exgcd(m[i],s/m[i],x,y);
83         (res+=y*s/m[i]*ans[i])%=s;
84         //cout<<y*s/m[i]*ans[i]<<endl;
85     }
86     printf("%lld",q_pow((res+s)%s));
87 }
View Code

 

T2 bzoj 3398 牡牛和牝牛

题目大意:

N只牛 这些牛公母任意 牛们要站成一排,任意两头公牛之间至少有k头母牛 

求有多少种排队方案(所有公牛可看做一样 母牛可看做一样)

思路:

dp i 表示前i头的方案 注意dp 1 =2(公母都可以取)

当这一头为母牛时 dp i+=dp i-1

为公牛时 dp i += dp i-k-1 当i<=k+1时 dp i++

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define inf 2139062143
11 #define ll long long
12 #define MAXN 100100
13 #define MOD 5000011
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 int n,dp[MAXN],k;
23 int main()
24 {
25     n=read(),k=read(),dp[1]=2;
26     for(int i=2;i<=n;i++)
27         if(i<=k+1) dp[i]=dp[i-1]+1;
28         else (dp[i]=dp[i-1]+dp[i-k-1])%=MOD;
29     printf("%d\n",dp[n]);
30 }
View Code

 

T3 luogu 1771 方程的解

题目大意:

正整数 k x 求不定方程a1+a2+...+ak=g(x) g(x)=x^x(mod 1000)的正整数解组数

思路:

先快速幂求出g(x) 然后相当于插板 g(x)-1个位置插k-1个板 高精度组合数即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define inf 2139062143
11 #define ll long long
12 #define MAXN 100100
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,MOD=1000;
22 int q_pow(int t,int p)
23 {
24     int res=1;
25     for(;p;p>>=1,(t*=t)%=MOD)
26         if(p&1) (res*=t)%=MOD;
27     return res;
28 }
29 struct bign 
30 {
31     int num[30],len;
32     bign(){memset(num,0,sizeof(num));len=0;}
33     void print()
34     {
35         printf("%d",num[len]);
36         for(int i=len-1;i>=0;i--) printf("%09d",num[i]);
37     }
38     bign operator + (const bign a) const
39     {
40         bign res;res.len=max(len,a.len);
41         for(int i=0;i<=res.len;i++)
42             res.num[i]+=num[i]+a.num[i],
43             res.num[i+1]=res.num[i]/MOD,res.num[i]%=MOD;
44         if(res.num[res.len+1]) res.len++;
45         return res;
46     }
47 }c[1010][1010];
48 int main()
49 {
50     n=read()-1,m=read(),m=q_pow(m%MOD,m)-1,MOD=1e9;
51     c[0][0].num[0]=1;
52     for(int i=1;i<=m;i++)
53     {
54         c[i][0].num[0]=1;
55         for(int j=1;j<=n&&j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
56     }
57     c[m][n].print();
58 }
View Code

 

T4 loj 10232 车的放置

题目大意:

形如这样的棋盘 求放k个互不攻击的车(jv) 的方案数

思路:

太菜了不会组合数 选择dp i j 表示前i行放了j个棋子的方案数

可以从i-1 行放了j 个棋子 与 前i-1行放了j-1个转移 后者需要乘这次的方案数

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define inf 2139062143
11 #define ll long long
12 #define MAXN 5010
13 #define MOD 100003
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 int a,b,c,d,k,f[MAXN][MAXN],v[MAXN];
23 int main()
24 {
25     a=read(),b=read(),c=read(),d=read(),k=read();
26     for(int i=0;i<=b+d;i++) f[i][0]=1;
27     for(int i=1;i<=b+d;i++)
28         for(int j=1;j<=k&&j<=i;j++)
29             if(i<=b) f[i][j]=(f[i-1][j]+f[i-1][j-1]*(a-j+1))%MOD;
30             else f[i][j]=(f[i-1][j]+f[i-1][j-1]*(a+c-j+1))%MOD;
31     printf("%d",f[b+d][k]);
32 }
View Code

 

T5 bzoj 3505 数三角形

题目大意:

给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个(三点不共线)

思路:

先算出选三个点的方案数再减去共线的方案数

枚举每个三点共线构成线段的这个向量

对于每个向量的方案为可以平移到的位置即(n-i)*(m-j)再乘线段上选点的方案数即gcd(i,j)-1

因为i j为正整数即假设这个线段一端为网格左下角 而左上角的方案相同因此每个向量方案再乘二

但i j 其中一个等于0时不需要乘2因为平移时已经算过了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #define inf 2139062143
11 #define ll long long
12 #define MAXN 5010
13 #define MOD 100003
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 ll n,m,ans;
23 int gcd(int a,int b) {if(!a) return b;return !b?a:gcd(b,a%b);}
24 int main()
25 {
26     n=read()+1,m=read()+1,ans=n*m*(n*m-1)*(n*m-2)/6;
27     for(ll i=0;i<=n;i++)
28         for(ll j=0;j<=m;j++)
29             if(i+j) ans-= ((i*j)?2LL:1LL)*(gcd(i,j)-1LL)*(n-i)*(m-j);
30     printf("%lld",ans);
31 }
View Code

 

posted @ 2018-10-19 15:10  jack_yyc  阅读(148)  评论(0编辑  收藏  举报