質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

508閲覧

C++ ABC178C 型の違いだけでWAのものがACになる理由とは?

mjk

総合スコア303

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/09/13 17:41

編集2020/09/13 19:50

問題:ABC178C
公式解説
公式解説コード
※すでにAC済みなので解法を知りたいという質問ではありません。

質問

公式解説を見ながら提出してWAとなった原因が分からず、
何故型の違いだけでWAになるのか理由が知りたいので分かる方はご教示ください。
よろしくお願いします。

試したこと

テストケースがまだ公開されていないようでどういったテストケースでWA(WA5/AC15/ALL20)となっているのか不明です。

自分は unsigned long long を使っていたので型の違いを変更する前は、
10^N -9^N -9^Nまでの途中の内部的な計算結果のようなもの?が負数になっていることで、
unsigned long long で扱えない為結果がWAとなっていると推測しました。

そこで次のように計算順序を変更してみましたが結果は変わらずWAでした。
変更前:ll ans=powmod(10,n)-powmod(9,n)-powmod(9,n)+powmod(8,n);
変更後:ll ans=powmod(10,n)+powmod(8,n)-powmod(9,n)-powmod(9,n);

最後に型を全て long long に変更することでACとなりました。
unsigned long long の方がlong longよりも扱える数が大きいし途中計算でも負数になっていないはずです。
何故型の違いだけでWAになるのか理由が分かりません。

例えばN=2の時の手計算は、(10^2=100 - 9^2=81 - 9^2=81 + 8^2=64) = 2 の結果となります。
100-91-91 の時点で一時的に負数になるのは分かるのですが、

計算順序を変えると、(10^2=100 + 8^2=64- 9^2=81 - 9^2=81) = 2 当然同じ結果ですが、
途中計算では100 + 64 - 81 -81 と左から順に計算していれば負数になることはありません

この部分以外で型が影響している箇所は無いと思ったのですが何かお気づきになりましたらご教示ください。

#追記:
※回答頂き途中計算を手計算したところ負数になっていました。
累乗計算の結果が負数にならないという思い込みから%MODの剰余で負数になることを想定出来なかったことが原因の実装ミスでした。
公式コードで long long を使っている理由がやっと理解出来ました。
ありがとうございました。

イメージ説明

C++

1//公式で long longとなっている箇所全てを 2typedef long long ll; 3 4//自分は unsigned long long としていた箇所を全てlong longにしたらACとなった。 5using ull = unsigned long long;

inout

1// unsigned long long; 2// in 3// 1000000 4 5// 907328795 6// 803957911 7// 961835147 8// 961835147 9 10// out 11// 369960420 12 13// using ll = long long; 14// in 15// 1000000 16 17// 907328795 18// 803957911 19// 961835147 20// 961835147 21 22// out 23// 787616419

###公式解説コード

C++

1#include<bits/stdc++.h> 2using namespace std; 3typedef long long ll; 4const ll mod=1000000007; 5 6ll powmod(ll x,ll y){ 7 ll res=1; 8 for(ll i=0;i<y;i++){ 9 res=res*x%mod; 10 } 11 return res; 12} 13int main(){ 14 ll n; 15 cin>>n; 16 ll ans=powmod(10,n)-powmod(9,n)-powmod(9,n)+powmod(8,n); 17 ans%=mod; 18 ans=(ans+mod)%mod; 19 cout<<ans<<"\n"; 20}

INPUT

12

OUTPUT

12

開発環境

Win10 (10.0.18362)
VSC1.48.2
C++17
gcc version 10.2.0 (Rev1, Built by MSYS2 project)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

powmodの返す値が、ただの累乗であれば、おっしゃっている通り、計算が途中で負になることはないでしょう。しかし実際に返しているのは、累乗の結果を1000000007で割ったあまりです。元の累乗の大小と累乗の余りの大小は、必ずしも一致しません。このため、計算結果自体が負になる可能性があります。

例えば、仮にpowmod7の余りを返すとします。するとN=2のとき、元の累乗の計算は

100 + 64 - 81 - 81 = 2

ですが、7の余りで計算していくと

(100 mod 7) + (64 mod 7) - (81 mod 7) - (81 mod 7) = 2 + 1 - 4 - 4 = -5

になります。

投稿2020/09/13 18:54

Bearded-Ockham

総合スコア430

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mjk

2020/09/13 19:42

回答頂きありがとうございます。 ご指摘の通り問題の入力最大値を手計算するとpowmodの戻り値4つを合計するところで負数になっていました。 累乗計算の結果は負数にならないという思い込みでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問