• 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 ;
    }
    /*
    
    */
    	
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    Javascript获取本周,本月,本季,本年,上月,上周,上季,去年,上二周,上二月
    SQL SERVER 2008 评估期已过的解决办法
    习惯那些“小事”
    Oracle 测试语句
    整理js常用按键相关代码
    .NET 学习笔记
    lamda表达式学习
    使用Html.DropDownList
    ibatis
    MyBatis
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/14816670.html
Copyright © 2020-2023  润新知