AtCoder Beginner Contest 200 D、E

D - Happy Birthday! 2

两个不同的序列总和相同,而且先取模200,那么根据容斥,第201次搜索就一定会找到答案。搜两个不同的序列,直接令n = min(8 , n)使用压位。

E - Patisserie ABC 2

直接枚举第一个数字就行。然后看当前数组对应的方案数,找到具体的某一个之后,再看第二个数字。

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) << "
" ;
  				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 ;
}
/*

*/
	
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/14816670.html