結果

問題 No.2568 列辞書順列列
ユーザー viral8viral8
提出日時 2023-12-02 16:11:55
言語 Java21
(openjdk 21)
結果
AC  
実行時間 641 ms / 3,000 ms
コード長 18,032 bytes
コンパイル時間 4,334 ms
コンパイル使用メモリ 86,724 KB
実行使用メモリ 80,036 KB
最終ジャッジ日時 2023-12-02 16:12:20
合計ジャッジ時間 21,699 ms
ジャッジサーバーID
(参考情報)
judge15 / judge10
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 50 ms
54,140 KB
testcase_01 AC 51 ms
54,128 KB
testcase_02 AC 352 ms
59,468 KB
testcase_03 AC 322 ms
61,576 KB
testcase_04 AC 518 ms
80,036 KB
testcase_05 AC 550 ms
79,984 KB
testcase_06 AC 525 ms
80,000 KB
testcase_07 AC 578 ms
79,884 KB
testcase_08 AC 532 ms
79,912 KB
testcase_09 AC 580 ms
78,844 KB
testcase_10 AC 557 ms
78,808 KB
testcase_11 AC 579 ms
78,872 KB
testcase_12 AC 607 ms
78,864 KB
testcase_13 AC 641 ms
79,160 KB
testcase_14 AC 583 ms
78,980 KB
testcase_15 AC 627 ms
76,888 KB
testcase_16 AC 608 ms
78,884 KB
testcase_17 AC 616 ms
78,744 KB
testcase_18 AC 624 ms
78,976 KB
testcase_19 AC 614 ms
78,804 KB
testcase_20 AC 592 ms
77,244 KB
testcase_21 AC 617 ms
78,872 KB
testcase_22 AC 580 ms
78,744 KB
testcase_23 AC 603 ms
78,784 KB
testcase_24 AC 581 ms
78,900 KB
testcase_25 AC 606 ms
78,796 KB
testcase_26 AC 603 ms
78,884 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import java.util.*;
import java.io.*;
import java.awt.Point;
import java.math.BigInteger;
class Main{
	private static final BufferedReader br =
		new BufferedReader(new InputStreamReader(System.in));
	private static final PrintWriter out =
		new PrintWriter(System.out);
	public static void main(String[] args)throws IOException{

		final int mod = 998244353;

		String[] str = br.readLine().split(" ");
		int N = Integer.parseInt(str[0]);
		int M = Integer.parseInt(str[1]);
		int Q = Integer.parseInt(str[2]);
		long[] subA = new long[N+1];
		str = br.readLine().split(" ");
		for(int i=0;i<N;i++){
			subA[i+1] = subA[i]*M%mod+Integer.parseInt(str[i])-1;
			if(subA[i+1]>=mod)
				subA[i+1] -= mod;
		}
		while(Q-->0){
			str = br.readLine().split(" ");
			int l = Integer.parseInt(str[0]);
			int r = Integer.parseInt(str[1]);
			long ans = (subA[r]-subA[l-1]*MathFunction.modPow(M,r-l+1,mod)%mod+1)%mod;
			out.println((mod+ans)%mod);
		}

		br.close();
		out.close();
	}
}

public final class MathFunction {

	private static final long[] numberForPrime = {2, 7, 61, 325, 9375, 28178, 450775, 9780504, 1795265022};

	/**
	 * aとbの最大公約数を求めます。戻り値は0以上であることが保証されます。
	 *
	 * @param a 公約数を求める整数
	 * @param b 公約数を求める整数
	 *
	 * @return aとbの最大公約数
	 */
	public static long gcd ( long a, long b ) {
		a = Math.abs( a );
		b = Math.abs( b );
		if ( b == 0 ) {
			return a;
		}
		long temp;
		while ( ( temp = a % b ) != 0 ) {
			a = b;
			b = temp;
		}
		return b;
	}

	/**
	 * aとbの最小公倍数を求めます。
	 * オーバーフロー検知は出来ません。
	 *
	 * @param a 公倍数を求める整数
	 * @param b 公倍数を求める整数
	 *
	 * @return aとbの最小公倍数
	 */
	public static long lcm ( final long a, final long b ) {
		return a / gcd( a, b ) * b;
	}

	/**
	 * 引数が素数か判定します。
	 *
	 * @param n 検査対象
	 *
	 * @return numが素数であるならtrue、素数でないならfalse
	 */
	public static boolean isPrime ( long n ) {
		n = Math.abs( n );
		if ( n == 2 ) {
			return true;
		}
		if ( n == 1 || ( n & 1 ) == 0 ) {
			return false;
		}
		long d = n - 1;
		while ( ( d & 1 ) == 0 ) {
			d >>= 1;
		}
		for ( final long a: numberForPrime ) {
			if ( a >= n ) {
				return true;
			}
			long t = d;
			long y = bigModPow( a, t, n );
			while ( t < n - 1 && y != 1 && y != n - 1 ) {
				y = bigModPow( y, 2, n );
				t <<= 1;
			}
			if ( y != n - 1 && ( t & 1 ) == 0 ) {
				return false;
			}
		}
		return true;
	}

	/**
	 * a**b mod mを計算します。
	 * Bigintegerを用いるのでオーバーフローは起こりません。
	 * 
	 * @param a
	 * @param b
	 * @param m
	 * @return a**b mod m
	 */
	private static long bigModPow ( final long a, final long b, final long m ) {
		return BigInteger.valueOf( a ).modPow( BigInteger.valueOf( b ), BigInteger.valueOf( m ) ).longValue();
	}

	/**
	 * num以下の素数を列挙します。
	 *
	 * @param num 素数を探す上限値
	 *
	 * @return num以下の素数のint型配列
	 */
	public static int[] primes ( final int num ) {
		if ( num < 2 ) {
			return new int[0];
		}
		final BitSet numbers = new BitSet( num + 1 );
		numbers.set( 2, num + 1 );
		final int limit = ( int )Math.sqrt( num );
		for ( int i = 2; i <= limit; ++i ) {
			if ( numbers.get( i ) ) {
				for ( int j = i * i; j <= num; j += i ) {
					numbers.clear( j );
				}
			}
		}
		final int[] answer = new int[numbers.cardinality()];
		int i = 2, index = 0;
		do {
			i = numbers.nextSetBit( i );
			answer[index++] = i++;
		} while ( index != answer.length );
		return answer;
	}

	/**
	 * a**bを計算します。
	 *
	 * @param a 被累乗数
	 * @param b 指数
	 *
	 * @return a**b
	 */
	public static long pow ( long a, long b ) {
		long ans = 1;
		while ( b > 0 ) {
			if ( ( b & 1 ) == 1 ) {
				ans *= a;
			}
			a *= a;
			b >>= 1;
		}
		return ans;
	}

	/**
	 * a**bをmodで割ったあまりを計算します。
	 *
	 * @param a 被累乗数
	 * @param b 指数
	 * @param mod 法とする整数
	 *
	 * @return a**bをmodで割ったあまり
	 */
	public static long modPow ( long a, long b, final long mod ) {
		long ans = 1;
		a %= mod;
		while ( b > 0 ) {
			if ( ( b & 1 ) == 1 ) {
				ans *= a;
			}
			ans %= mod;
			a *= a;
			a %= mod;
			b >>= 1;
		}
		return ans;
	}

	/**
	 * nCrを計算します。
	 *
	 * @param n 二項係数を求めるのに用いる値
	 * @param r 二項係数を求めるのに用いる値
	 *
	 * @return nCr
	 */
	public static long combi ( final long n, long r ) {
		if ( r < 0 || n < r ) {
			return 0;
		}
		long ans = 1;
		r = Math.min( n - r, r );
		for ( int i = 0; i < r; ++i ) {
			ans *= n - i;
			ans /= i + 1;
		}
		return ans;
	}

	/**
	 * nCrをmodで割ったあまりを計算します。
	 *
	 * @param n 二項係数を求めるのに用いる値
	 * @param r 二項係数を求めるのに用いる値
	 * @param mod 法とする整数
	 *
	 * @return nCrをmodで割ったあまり
	 */
	public static long modCombi ( final long n, long r, final long mod ) {
		if ( r < 0 || n < r ) {
			return 0;
		}
		long ans = 1;
		r = Math.min( n - r, r );
		for ( int i = 0; i < r; ++i ) {
			ans *= n - i;
			ans %= mod;
			ans *= modPow( i + 1, mod - 2, mod );
			ans %= mod;
		}
		return ans;
	}

	/**
	 * 引数の前半二点、後半二点で構成される二線分が交差しているか返します。
	 *
	 * @param x1 点1のx座標
	 * @param y1 点1のy座標
	 * @param x2 点2のx座標
	 * @param y2 点2のy座標
	 * @param x3 点3のx座標
	 * @param y3 点3のy座標
	 * @param x4 点4のx座標
	 * @param y4 点4のy座標
	 *
	 * @return 交差している(線分の端が他方の線分上に存在する場合も含む)場合は1、同一線分直線上なら0、それ以外は-1
	 */
	public static int isCrossed ( final int x1, final int y1,
			final int x2, final int y2,
			final int x3, final int y3,
			final int x4, final int y4 ) {
		final long s1 = ( long )( x1 - x2 ) * ( y3 - y1 ) - ( long )( y1 - y2 ) * ( x3 - x1 );
		final long t1 = ( long )( x1 - x2 ) * ( y4 - y1 ) - ( long )( y1 - y2 ) * ( x4 - x1 );
		final long s2 = ( long )( x3 - x4 ) * ( y1 - y3 ) - ( long )( y3 - y4 ) * ( x1 - x3 );
		final long t2 = ( long )( x3 - x4 ) * ( y2 - y3 ) - ( long )( y3 - y4 ) * ( x2 - x3 );
		final long temp1 = s1 * t1;
		final long temp2 = s2 * t2;
		if ( temp1 > 0 || temp2 > 0 ) {
			return -1;
		}
		if ( temp1 == 0 && temp2 == 0 ) {
			return 0;
		}
		return 1;
	}

	/**
	 * 引数の前半二点、後半二点で構成される二線分が交差しているか返します。
	 *
	 * @param p1 点1
	 * @param p2 点2
	 * @param p3 点3
	 * @param p4 点4
	 *
	 * @return 交差している(線分の端が他方の線分上に存在する場合も含む)場合は1、同一線分直線上なら0、それ以外は-1
	 */
	public static int isCrossed ( final Point p1, final Point p2, final Point p3, final Point p4 ) {
		return isCrossed( p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y );
	}

	/**
	 * numをmodで割ったあまりを返します。
	 * 戻り値は0以上mod未満であることが保証されます。
	 *
	 * @param num 被除算数
	 * @param mod 法とする値
	 *
	 * @return numをmodで割ったあまり
	 */
	public static long remainder ( long num, final long mod ) {
		num %= mod;
		if ( num < 0 ) {
			num += mod;
		}
		return num;
	}

	/**
	 * numが何桁かを返します。
	 * 0は1桁として捉えます。
	 *
	 * @param num 調べる整数
	 *
	 * @return numの桁数
	 */
	public static int digit ( final long num ) {
		if ( num < 10L ) {
			return 1;
		}
		if ( num < 100L ) {
			return 2;
		}
		if ( num < 1000L ) {
			return 3;
		}
		if ( num < 10000L ) {
			return 4;
		}
		if ( num < 100000L ) {
			return 5;
		}
		if ( num < 1000000L ) {
			return 6;
		}
		if ( num < 10000000L ) {
			return 7;
		}
		if ( num < 100000000L ) {
			return 8;
		}
		if ( num < 1000000000L ) {
			return 9;
		}
		if ( num < 10000000000L ) {
			return 10;
		}
		if ( num < 100000000000L ) {
			return 11;
		}
		if ( num < 1000000000000L ) {
			return 12;
		}
		if ( num < 10000000000000L ) {
			return 13;
		}
		if ( num < 100000000000000L ) {
			return 14;
		}
		if ( num < 1000000000000000L ) {
			return 15;
		}
		if ( num < 10000000000000000L ) {
			return 16;
		}
		if ( num < 100000000000000000L ) {
			return 17;
		}
		if ( num < 1000000000000000000L ) {
			return 18;
		}
		return 19;
	}

	/**
	 * 渡された値の最大値を求めます。
	 * @param nums
	 * @return
	 */
	public static int max ( final int... nums ) {
		int ans = Integer.MIN_VALUE;
		for ( int num: nums ) {
			ans = Math.max( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最大値を求めます。
	 * @param nums
	 * @return
	 */
	public static long max ( final long... nums ) {
		long ans = Long.MIN_VALUE;
		for ( long num: nums ) {
			ans = Math.max( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最大値を求めます。
	 * @param nums
	 * @return
	 */
	public static double max ( final double... nums ) {
		double ans = -Double.MIN_VALUE;
		for ( double num: nums ) {
			ans = Math.max( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最大値を求めます。
	 * @param nums
	 * @return
	 */
	public static <E extends Comparable<E>> E max ( final E[] nums ) {
		E ans = nums[0];
		for ( E value: nums ) {
			if ( ans.compareTo( value ) > 0 ) {
				ans = value;
			}
		}
		return ans;
	}

	/**
	 * 渡された値の最小値を求めます。
	 * @param nums
	 * @return
	 */
	public static int min ( final int... nums ) {
		int ans = Integer.MAX_VALUE;
		for ( int num: nums ) {
			ans = Math.min( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最小値を求めます。
	 * @param nums
	 * @return
	 */
	public static long min ( final long... nums ) {
		long ans = Long.MAX_VALUE;
		for ( long num: nums ) {
			ans = Math.min( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最小値を求めます。
	 * @param nums
	 * @return
	 */
	public static double min ( final double... nums ) {
		double ans = Double.MAX_VALUE;
		for ( double num: nums ) {
			ans = Math.min( ans, num );
		}
		return ans;
	}

	/**
	 * 渡された値の最小値を求めます。
	 * @param nums
	 * @return
	 */
	public static <E extends Comparable<E>> E min ( final E[] nums ) {
		E ans = nums[0];
		for ( E value: nums ) {
			if ( ans.compareTo( value ) < 0 ) {
				ans = value;
			}
		}
		return ans;
	}

	/**
	 * 渡された値の総和を求めます。
	 * @param nums
	 * @return
	 */
	public static long sum ( final int... nums ) {
		long ans = 0;
		for ( int num: nums ) {
			ans += num;
		}
		return ans;
	}

	/**
	 * 渡された値の総和を求めます。
	 * @param nums
	 * @return
	 */
	public static long sum ( final long... nums ) {
		long ans = 0;
		for ( long num: nums ) {
			ans += num;
		}
		return ans;
	}

	/**
	 * 渡された値の総和をmodで割ったあまりを求めます。
	 * @param nums
	 * @param mod
	 * @return
	 */
	public static long modSum ( final long mod, final int... nums ) {
		long ans = 0;
		for ( int num: nums ) {
			ans += num;
			ans %= mod;
		}
		if ( ans < 0 ) {
			ans += mod;
		}
		return ans;
	}

	/**
	 * 渡された値の総和をmodで割ったあまりを求めます。
	 * @param nums
	 * @param mod
	 * @return
	 */
	public static long modSum ( final long mod, final long... nums ) {
		long ans = 0;
		for ( long num: nums ) {
			ans += num;
			ans %= mod;
		}
		if ( ans < 0 ) {
			ans += mod;
		}
		return ans;
	}

	/**
	 * 渡された配列の指定された区間の総和を求めます。
	 * @param nums
	 * @param from
	 * @param to
	 * @return
	 */
	public static long sum ( final int[] nums, int from, int to ) {
		long ans = 0;
		for ( int i = from; i < to; ++i ) {
			ans += nums[i];
		}
		return ans;
	}

	/**
	 * 渡された配列の指定された区間の総和を求めます。
	 * @param nums
	 * @param from
	 * @param to
	 * @return
	 */
	public static long sum ( final long[] nums, int from, int to ) {
		long ans = 0;
		for ( int i = from; i < to; ++i ) {
			ans += nums[i];
		}
		return ans;
	}

	/**
	 * 渡された配列の指定された区間の総和をmodで割ったあまりを求めます。
	 * @param nums
	 * @param from
	 * @param to
	 * @param mod
	 * @return
	 */
	public static long modSum ( final int[] nums, int from, int to, long mod ) {
		long ans = 0;
		for ( int i = from; i < to; ++i ) {
			ans += nums[i];
			ans %= mod;
		}
		if ( ans < 0 ) {
			ans += mod;
		}
		return ans;
	}

	/**
	 * 渡された配列の指定された区間の総和をmodで割ったあまりを求めます。
	 * @param nums
	 * @param from
	 * @param to
	 * @param mod
	 * @return
	 */
	public static long modSum ( final long[] nums, int from, int to, long mod ) {
		long ans = 0;
		for ( int i = from; i < to; ++i ) {
			ans += nums[i];
			ans %= mod;
		}
		if ( ans < 0 ) {
			ans += mod;
		}
		return ans;
	}

	/**
	 * 引数numがl以上r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含まない)
	 *
	 * @return l <= num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheck ( final int num, final int l, final int r ) {
		return l <= num && num < r;
	}

	/**
	 * 引数numがl以上r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含まない)
	 *
	 * @return l <= num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheck ( final long num, final long l, final long r ) {
		return l <= num && num < r;
	}

	/**
	 * 引数numがl以上r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含まない)
	 *
	 * @return l <= num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheck ( final double num, final double l, final double r ) {
		return l <= num && num < r;
	}

	/**
	 * 引数numがl以上r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含まない)
	 *
	 * @return l <= num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static <E extends Comparable<E>> boolean rangeCheck ( final E num, final E l, final E r ) {
		return 0 <= l.compareTo( num ) && 0 < num.compareTo( r );
	}

	/**
	 * 引数numがlより大きく、r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含まない)
	 * @param r 上限(rを含まない)
	 *
	 * @return l < num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckOpen ( final int num, final int l, final int r ) {
		return l < num && num < r;
	}

	/**
	 * 引数numがlより大きく、r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含まない)
	 * @param r 上限(rを含まない)
	 *
	 * @return l < num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckOpen ( final long num, final long l, final long r ) {
		return l < num && num < r;
	}

	/**
	 * 引数numがlより大きく、r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含まない)
	 * @param r 上限(rを含まない)
	 *
	 * @return l < num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckOpen ( final double num, final double l, final double r ) {
		return l < num && num < r;
	}

	/**
	 * 引数numがlより大きく、r未満の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含まない)
	 * @param r 上限(rを含まない)
	 *
	 * @return l < num < rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static <E extends Comparable<E>> boolean rangeCheckOpen ( final E num, final E l, final E r ) {
		return 0 < l.compareTo( num ) && 0 < num.compareTo( r );
	}

	/**
	 * 引数numがl以上r以下の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含む)
	 *
	 * @return l <= num <= rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckClose ( final int num, final int l, final int r ) {
		return l <= num && num <= r;
	}

	/**
	 * 引数numがl以上r以下の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含む)
	 *
	 * @return l <= num <= rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckClose ( final long num, final long l, final long r ) {
		return l <= num && num <= r;
	}

	/**
	 * 引数numがl以上r以下の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含む)
	 *
	 * @return l <= num <= rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static boolean rangeCheckClose ( final double num, final double l, final double r ) {
		return l <= num && num <= r;
	}

	/**
	 * 引数numがl以上r以下の範囲内か判定します。
	 *
	 * @param num 判定する値
	 * @param l 下限(lを含む)
	 * @param r 上限(rを含む)
	 *
	 * @return l <= num <= rを満たしていればtrue 、 満たしていなければfalse
	 */
	public static <E extends Comparable<E>> boolean rangeCheckClose ( final E num, final E l, final E r ) {
		return 0 <= l.compareTo( num ) && 0 <= num.compareTo( r );
	}
}
0