ABC357A～Fの解答[Java]

## はじめに
今回はコンテスト中にEまで、コンテスト後にFを解いたのでFまで載せようと思います。

なお、僕のライブラリは[提出結果](https://atcoder.jp/contests/abc357/submissions?f.Task=&f.LanguageName=Java&f.Status=AC&f.User=viral)よりご確認ください。
では、見ていきましょう。

## A - Sanitize Hands
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_a)

$H$を順に受け取って、$M$が$0$を下回ってしまうタイミングを探しました。
```A.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	public static void main(String[] args){

		//N、Mの受け取り
		int N = sc.nextInt();
		int M = sc.nextInt();

  		//Mが0を下回るときを調べる
		for(int i=0;i<N;i++){
			int H = sc.nextInt();
			if(M<H){
				System.out.println(i);
				return;
			}
			M -= H;
		}

  		//ループを抜けた=全員消毒できたのでN
		out.println(N);

		out.close();
	}
}
```

## B - Uppercase and Lowercase
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_b)

先頭から愚直に小文字と大文字の個数を調べて問題文の通りに変換しました。
```B.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	public static void main(String[] args){

		//Sの受け取り
		String S = sc.next();

  		//小文字の個数-大文字の個数を求める
		int count = 0;
		for(char c:S.toCharArray())
			count += c<'a'?1:-1;

   		//条件に応じて変換
		out.println(count<0?S.toLowerCase():S.toUpperCase());

		out.close();
	}
}
```

## C - Sierpinski carpet
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_c)

各レベルのカーペットは再帰的に定義されているので、どの位置がレベルいくつになるかを再帰メソッドを定義することで解きました。
```C.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	public static void main(String[] args){

		//Nの受け取り
		int N = sc.nextInt();

  		//再帰で答えを構築
		char[][] ans = new char[(int)MathFunction.pow(3,N)][(int)MathFunction.pow(3,N)];
		fill(ans,0,0,N);

  		//答えの出力
		out.println(ans);

		out.close();
	}

 	//再帰メソッド(構築用配列、開始座標、レベルを引数に)
	private static void fill(char[][] ans,int x,int y,int N){

 		//レベル0は1マスだけなのでその場で構築
		if(N==0){
			ans[x][y] = '#';
			return;
		}

  		//レベル1以上は再帰しながら構築
		else{
			int subN = (int)MathFunction.pow(3,N-1);
			for(int i=0;i<3;i++){
				for(int j=0;j<3;j++){
					if(i==1&&j==1){
						for(int k=0;k<subN;k++){
							for(int l=0;l<subN;l++){
								ans[x+subN+k][y+subN+l] = '.';
							}
						}
					}
					else{
						fill(ans,x+subN*i,y+subN*j,N-1);
					}
				}
			}
		}
	}
}
```

## D - 88888888
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_d)

$N$の桁数を$S$とすると、$V_N=\sum_{i=1}^N{N \times (10^S)^{i-1}}$となることから、
$$V_N=\sum_{i=1}^N{N \times (10^S)^{i-1}}=N \times \sum_{i=1}^N{(10^S)^{i-1}}=N \times \frac{(10^S)^N-1}{10^S-1}$$
と変形することができます。法が素数なので、容易に逆元が求まることから、これを実装することで問題を解きました。
```D.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	private static final int MOD = 998244353;

	public static void main(String[] args){

		//nの受け取り
		long N = sc.nextLong();

  		//上記の式の値を構築(rは10^Sに該当)
		long ans = N%MOD;
		long r = MathFunction.modPow(10,MathFunction.digit(N),MOD);
		ans *= MathFunction.modPow(r,N,MOD)-1;
		ans %= MOD;
		ans *= MathFunction.modPow((MOD+r-1)%MOD,MOD-2,MOD);
		ans %= MOD;

  		//答えの出力
		out.println((ans%MOD+MOD)%MOD);

		out.close();
	}
}
```
式変形にめちゃくちゃ手こずりました…。

## E - Reachability in Functional Graph
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_e)

[AtCoderLibraryForJava](https://github.com/NASU41/AtCoderLibraryForJava)のSCCを使って解きました。
強連結成分毎に遷移しながら、順に移動できる頂点の組を数え上げることで高速に解くことができます。
```E.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	public static void main(String[] args){

		//Nの受け取り
		int N = sc.nextInt();

  		//隣接リストとSCCを同時構築
		ArrayList<ArrayList<Integer>> list = new ArrayList<>();
		for(int i=0;i<N;i++)
			list.add(new ArrayList<>());
		SCC scc = new SCC(N);
		for(int i=0;i<N;i++){
			int a = sc.nextInt()-1;
			list.get(a).add(i);
			scc.addEdge(a,i);
		}

  		//強連結成分ごとに遷移するDPで数え上げ
		int[][] graph = scc.build();
		long[] dp = new long[graph.length];
		long ans = 0;
		for(int i=0;i<graph.length;i++){
			HashSet<Integer> set = new HashSet<>();
			for(int now:graph[i])
				for(int next:list.get(now))
					set.add(scc.id(next));
			set.remove(i);
			long sum = dp[i]+graph[i].length;
			for(int next:set)
				dp[next] += sum;
			ans += dp[i]+(long)graph[i].length*graph[i].length;
		}

  		//答えの出力
		out.println(ans);

		out.close();
	}
}
```
SCCの実装は上記のリンク先よりご確認ください。

## F - Two Sequence Queries
問題文は[こちら](https://atcoder.jp/contests/abc357/tasks/abc357_f)

[公式解説](https://atcoder.jp/contests/abc357/editorial/10186)の通りです。
```F.java
final class Main{
	private static final boolean autoFlush = false;
	private static final SimpleScanner sc = new SimpleScanner(System.in);
	private static final SimpleWriter out = new SimpleWriter(System.out,autoFlush);

	//遅延セグ木用クラス
	static class Node{
		long A,B,sum,length;
		public Node(long a,long b,long s,long l){
			A = a;
			B = b;
			sum = s;
			length = l;
		}
	}
	static class SubNode{
		long xA,xB;
		public SubNode(long a,long b){
			xA = a;
			xB = b;
		}
	}

	public static void main(String[] args){

		//N、Q、A、Bの受け取り
		int N = sc.nextInt();
		int Q = sc.nextInt();
		int[] A = sc.nextInt(N);
		int[] B = sc.nextInt(N);

  		//遅延セグ木構築
		Node[] node = new Node[N];
		for(int i=0;i<N;i++)
			node[i] = new Node(A[i],B[i],(long)A[i]*B[i]%998244353,1);
		LazySegmentTree<Node,SubNode> lSegT = new LazySegmentTree<>(node,new Node(0,0,0,0),new SubNode(0,0),true){
			final int MOD = 998244353;
			public Node function(Node a,Node b){
				return new Node(
					(a.A+b.A)%MOD,
					(a.B+b.B)%MOD,
					(a.sum+b.sum)%MOD,
					a.length+b.length
				);
			}
			public Node mapping(Node a,SubNode f){
				long A = (a.A+f.xA*a.length)%MOD;
				long B = (a.B+f.xB*a.length)%MOD;
				long sum = (a.sum+A*f.xB+a.B*f.xA)%MOD;
				return new Node(A,B,sum,a.length);
			}
			public SubNode composition(SubNode fa,SubNode fb){
				return new SubNode(
					(fa.xA+fb.xA)%MOD,
					(fa.xB+fb.xB)%MOD
				);
			}
		};

  		//クエリ処理
		while(Q-->0){
			int t = sc.nextInt();
			if(t==1){
				int l = sc.nextInt();
				int r = sc.nextInt();
				int x = sc.nextInt();
				lSegT.apply(l,r+1,new SubNode(x,0));
			}
			if(t==2){
				int l = sc.nextInt();
				int r = sc.nextInt();
				int x = sc.nextInt();
				lSegT.apply(l,r+1,new SubNode(0,x));
			}
			if(t==3){
				int l = sc.nextInt();
				int r = sc.nextInt();
				out.println(lSegT.query(l,r+1).sum);
			}
		}

		out.close();
	}
}
```
遅延セグ木でいけそう、ということしか気づけなかった…。

## 感想
A,B:易しい
C:一瞬ウッてなった
D:かなり時間をかけてしまった…
E:SCCでいけそうな気はしたが、ACL4Javaを取ってくるのが面倒で横着して時間をかけた…
F:何載せれば良いかがわからなかった…経験不足…
って感じでした。

うぅ…レート下がり続きで辛い…。