AtCoder Beginner Contest 200 D、E
两个不同的序列总和相同,而且先取模200,那么根据容斥,第201次搜索就一定会找到答案。搜两个不同的序列,直接令n = min(8 , n)使用压位。
直接枚举第一个数字就行。然后看当前数组对应的方案数,找到具体的某一个之后,再看第二个数字。
dp[i],表示三者之和为i的方案数。
\[dp[m] = \sum_{i = m - 2n}^{min(m - 2 , n)}D[m - i]
\]
D[m]表示两个位置上如何放置的方案数。每个位置上范围都是[1 , n]
设第二个位置上为t,那么第三个位置上为m - t
\[1<=t <= n\\
1<=m - t <= n\\
max(1 , m - n)<=t <= min(m - 1, n)\\
D[m] = min(m - 1 , n) - max(1 , m - n) + 1 \\
\]
然后对D求个前缀和,然后求得dp[i]
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#include <bitset>
#include <deque>
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second
#define pb push_back
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 3e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int n ;
ll D[N] , dp[N] ;
ll k ;
int get(int m) {
int l = max(1 , m - n) , r = min(n , m - 1) ;
return r - l + 1 ;
}
int work()
{
cin >> n >> k ;
for(int i = 2 ;i <= 2 * n ;i ++ )
D[i] = get(i) , D[i] += 1ll * D[i - 1] ;
for(int i = 3 ;i <= 3 * n ;i ++ ) {
int m = i ;
int l = m - (min(m - 2 , n)) , r = m - max(1 , m - 2 * n) ;
dp[i] = D[r] - D[l - 1] ;
}
if(k == 1) return 0 * puts("1 1 1") ;
for(int i = 3; i <= 3 * n ;i ++ ) {
ll t = dp[i] ;
if(t < k) k -= t ;
else {
for(int j = 1; j <= min(i - 2, n); j ++ ) {
if(i - j > 2 * n) continue ;
int m = i - j ;
int l = max(1 , m - n) , r = min(n , m - 1) ;
if(k > r - l + 1) {
k -= r - l + 1 ;
continue ;
}
cout << j << " " << l + k - 1 << " " << m - (l + k - 1) << "\n" ;
return 0 ;
}
}
}
return 0 ;
}
int main()
{
// freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
// freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;
work() ;
return 0 ;
}
/*
*/
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。