結果

問題 No.213 素数サイコロと合成数サイコロ (3-Easy)
ユーザー 37zigen37zigen
提出日時 2016-05-08 20:58:14
言語 Java21
(openjdk 21)
結果
AC  
実行時間 208 ms / 3,000 ms
コード長 2,596 bytes
コンパイル時間 2,457 ms
コンパイル使用メモリ 78,200 KB
実行使用メモリ 43,856 KB
最終ジャッジ日時 2024-04-15 13:57:02
合計ジャッジ時間 3,430 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 208 ms
43,856 KB
testcase_01 AC 207 ms
43,836 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

package yukicoder;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
	public static void main(String[] args){
		new Main().solve();
	}
	final long mod =1_000_000_000+7;
	void solve(){
		Scanner sc=new Scanner(System.in);
		long n=sc.nextLong();
		int p=sc.nextInt();
		int c=sc.nextInt();
		//まず、さいころをP+C個振って和がK個になるパターン数をDPで数える。
		long[][] k=new long[p+c+1][13*(p+c)+1];
		k[0][0]=1;
		int[] prime={2,3,5,7,11,13};
		int[] composite={4,6,8,9,10,12};
		for(int l=0;l<6;l++){
			for(int i=0;i<p;i++){
				for(int j=0;j<k[0].length;j++){
					if(k[i][j]>0){
						k[i+1][j+prime[l]]+=k[i][j];
						k[i+1][j+prime[l]]%=mod;
					}
				}
			}
		}
		for(int l=0;l<6;l++){
			for(int i=0;i<c;i++){
				for(int j=0;j<k[0].length;j++){
					if(k[p+i][j]>0){
						k[p+i+1][j+composite[l]]+=k[p+i][j];
						k[p+i+1][j+composite[l]]%=mod;
					}
				}
			}
		}

		int n_k=k[0].length-1;
		long[][] A=new long[n_k][n_k];
		for(int i=0;i<n_k-1;i++)A[i][i+1]=1;
		for(int i=0;i<n_k;i++){
			A[n_k-1][i]=k[p+c][n_k-i];
		}

		//a[1]~a[n_k]を用意
		long[][] a=new long[n_k][1];
		
		for(int i=1;i<k[0].length;i++){
			//iはサイコロの目の和
			for(int j=0;j>-k[0].length;j--){
				//-jから出発した場合
				if(i+j>=1){
					a[i+j-1][0]+=k[p+c][i];
					a[i+j-1][0]%=mod;
				}
			}
		}
		for(int i=0;i<a.length;i++){
			for(int j=i-1;j>=0;j--){
				a[i][0]+=(k[p+c][i-j]*a[j][0])%mod;
				a[i][0]%=mod;
			}
		}
		long[] e=new long[a.length];
		for(int i=0;i<k[0].length-1;i++)e[i]=k[p+c][i+1];
		long[] aa=new long[a.length];
		for(int i=0;i<aa.length;i++)aa[i]=a[i][0];
		long ans=solve(n,e,aa,mod);
		System.out.println(ans);
	}
	//a[n]=e[0]a[n-1]+e[1]a[n-2]+...+e[K-1]a[n-K]:
		//a[i]=第i+1項目の値(初期条件)
		//第N項目を求める。
		long solve(long N,long[] e,long[] a,long mod){
			int K=e.length;
			long[] x=new long[K];
			long[] y=new long[K];
			x[1]=1;
			y[0]=1;
			for(long n=N-1;n>0;n>>=1,x=mul(x,x,e,mod)){
				if((n&1)==1)y=mul(y,x,e,mod);
			}
			long ans=0;
			for(int i=0;i<K;i++){
				ans=(ans+(long)y[i]*a[i])%mod;
			}
			return ans;
		}	
		long[] mul(long[] a,long[] b,long[] e,long mod){
			int K=e.length;
			int i,j;
			long[] c=new long[2*K];
			for(i=0;i<K;i++){
				for(j=0;j<K;j++){
					c[i+j]=(c[i+j]+a[i]*b[j])%mod;
				}
			}
			for(i=2*K-1;i>=K;i--){
				for(j=1;j<=K;j++){
					c[i-j]=(c[i-j]+e[j-1]*c[i])%mod;
				}
			}
			long[] d=new long[K];
			for(i=0;i<K;i++)d[i]=c[i];
			return d;
		}
	void tr(Object...o){System.out.println(Arrays.deepToString(o));}
}
0