teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

6

2019/05/14 00:51

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
File without changes

5

intをlong longに

2019/05/14 00:51

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
@@ -46,7 +46,7 @@
46
46
  cin>>N>>K;
47
47
 
48
48
  int k=0;
49
- int kk=K;
49
+ long long kk=K;
50
50
  while(kk)k++,kk>>=1;
51
51
 
52
52
  int odd=0,even=0;

4

微妙な言い間違いの修正

2019/05/13 10:18

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
@@ -77,7 +77,7 @@
77
77
  }
78
78
  ```
79
79
 
80
- しかしこのコードでは、数列の要素がKを超えた場合が考慮されていません。
80
+ しかしこのコードでは、数列の最後の要素がKを超えた場合が考慮されていません。
81
81
  たとえばN=3、K=2のとき、(1, 2, 3), (2, 1, 3)まで数えてしまうため、出力は5です。
82
82
  どのように書き換えれば __数列の要素がKを超えた場合__ を考慮できるかわからず、解決の糸口が見つからなかったため質問いたしました。
83
83
 

3

行間

2019/05/13 10:11

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
@@ -79,4 +79,10 @@
79
79
 
80
80
  しかしこのコードでは、数列の要素がKを超えた場合が考慮されていません。
81
81
  たとえばN=3、K=2のとき、(1, 2, 3), (2, 1, 3)まで数えてしまうため、出力は5です。
82
- どのように書き換えれば __数列の要素がKを超えた場合__ を考慮できるかわからず、解決の糸口が見つからなかったため質問いたしました。
82
+ どのように書き換えれば __数列の要素がKを超えた場合__ を考慮できるかわからず、解決の糸口が見つからなかったため質問いたしました。
83
+
84
+ ## 追記2
85
+
86
+ できればヒントだけでも教えていただけると嬉しいです。
87
+ ある程度の行間であれば頑張って対応いたします。
88
+ 回答よろしくお願いします。

2

2^50の制約が無考慮

2019/05/13 09:50

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
@@ -28,7 +28,7 @@
28
28
  #include <bits/stdc++.h>
29
29
  using namespace std;
30
30
 
31
- int dp[50][2];
31
+ int dp[52][2];
32
32
 
33
33
  int comb(int x,int y){
34
34
  if(x<0||y<0||x<y)return 0;

1

考えたこと追記

2019/05/13 09:44

投稿

toshiyan
toshiyan

スコア74

title CHANGED
File without changes
body CHANGED
@@ -4,4 +4,79 @@
4
4
 
5
5
  たとえば、N=3, K=2のとき、(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 0), (2, 0, 2), (2, 2, 0) の7通りが答えです。
6
6
 
7
- という問題を解きたいのですが、解くことができません。どのようにすれば解けるでしょうか?制約は N ≦ 1000, K ≦ 2^50 です。
7
+ という問題を解きたいのですが、解くことができません。どのようにすれば解けるでしょうか?制約は N ≦ 1000, K ≦ 2^50 です。
8
+
9
+ ## 追記
10
+
11
+ 考えたことを追記します。
12
+
13
+ ①__長さNのK以下の数列のXORが0の通り数__ (求めたいもの)
14
+ ②__長さN-1のK以下の数列のXORがK以下の通り数__
15
+ ③__長さN-1のK以下の数列のXORがKを超える通り数__
16
+
17
+ ①と②は等しいです。
18
+ なぜなら、②のXORの結果と同じ数値を後ろに付け足せば、①の数列になるからです。
19
+ そして、③は②の余事象であるため、③を求めることを考えました。
20
+ 以下のようなDPを考えます。
21
+
22
+ dp[i][j] := 上からiビット目まで見たときの通り数(jはKを超えたかどうか)
23
+
24
+ そして次のようなコードを書きました。
25
+ (オーバーフローは気にしない方向でお願いします)
26
+
27
+ ```cpp
28
+ #include <bits/stdc++.h>
29
+ using namespace std;
30
+
31
+ int dp[50][2];
32
+
33
+ int comb(int x,int y){
34
+ if(x<0||y<0||x<y)return 0;
35
+ int r=1;
36
+ for(int i=1;i<=y;++i){
37
+ r*=(x-i+1);
38
+ r/=i;
39
+ }
40
+ return r;
41
+ }
42
+
43
+ int main(){
44
+ int N;
45
+ long long K;
46
+ cin>>N>>K;
47
+
48
+ int k=0;
49
+ int kk=K;
50
+ while(kk)k++,kk>>=1;
51
+
52
+ int odd=0,even=0;
53
+ for(int i=1;i<=N-1;i+=2){
54
+ odd+=comb(N-1,i);
55
+ }
56
+ for(int i=0;i<=N-1;i+=2){
57
+ even+=comb(N-1,i);
58
+ }
59
+
60
+ dp[0][0]=1;
61
+ for(int i=0;i<k;++i){
62
+ for(int j=0;j<=1;++j){
63
+ if(j==1){
64
+ dp[i+1][j]+=dp[i][j]*(even+odd);
65
+ }else{
66
+ if((K&(1LL<<(k-i-1)))==0){
67
+ dp[i+1][1]+=dp[i][j]*odd;
68
+ dp[i+1][0]+=dp[i][j]*even;
69
+ }else{
70
+ dp[i+1][j]+=dp[i][j]*odd;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ cout<<pow(K+1,N-1)-dp[k][1]<<endl;
76
+ return 0;
77
+ }
78
+ ```
79
+
80
+ しかしこのコードでは、数列の要素がKを超えた場合が考慮されていません。
81
+ たとえばN=3、K=2のとき、(1, 2, 3), (2, 1, 3)まで数えてしまうため、出力は5です。
82
+ どのように書き換えれば __数列の要素がKを超えた場合__ を考慮できるかわからず、解決の糸口が見つからなかったため質問いたしました。