Educational Codeforces Round 80 (Rated for Div. 2)

\[Educational\ Codeforces\ Round\ 80\ (Rated\ for\ Div.\ 2)\]

A.Deadline

打勾函数找最小值,在\(\sqrt{d}\)邻域里找\(x\)最小化\(x+\lceil\frac{d}{x+1}\rceil\)即可

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int T,n,d;
typedef long long int LL;
int main(){
    ____();
    cin >> T;
    while(T--){
        cin >> n >> d;
        LL dd = sqrt(d);
        bool ok = false;
        for(LL x = max(0ll,dd-2); x <= dd+2; x++) if(x+d/(x+1)+(d%(x+1)!=0)<=n) ok = true;
        cout << (ok?"YES":"NO") << endl;
    }
    return 0;
}

B.Yet Another Meme Problem

\(1\le a \le A, 1\le b \le B\),问区间内满足\(a·b+a+b=a·10^{dig(b)}+b\),其中\(dig(b)\)为b的位数
化简之后得到\(b-1=10^{dig(b)}\),也就是形如9、99、999……之类的数,找到这样的数的个数,乘上\(A\)即可

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
int t;
LL a,b;
int main(){
    ____();
    cin >> t;
    while(t--){
        cin >> a >> b;
        LL cnt = 0,cur = 10;
        while(cur-1<=b){
            cnt++;
            cur*=10;
        }
        cout << cnt*a << endl;
    }
    return 0;
}

C.Two Arrays

有两个序列\(a\)和\(b\),问能够造出多少对满足\(a\)不减,\(b\)不增,且\(a[i]\le n,b[i]\le n,a[i]\le b[i]\ for\ all\ i\ from\ 1\ to\ m\)的序列
考虑\(dp[k][i][j]\)表示当前处理到第\(k\)位,\(a\)序列当前为\(i\),\(b\)序列当前为\(j\)的情况有多少种
状态转移方程:\(dp[k][i][j] = \sum_{a=1}^{i} \sum_{b=j}^{n}dp[k-1][a][b]\)
用二维前缀和维护一下即可

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
typedef int_fast64_t LL;
const LL MOD = 1e9+7;
const int MAXN = 1111;
int n,m;
LL f[11][MAXN][MAXN],sum[MAXN][MAXN];
int main(){
    ____();
    cin >> n >> m;
    for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++) f[1][i][j] = 1;
    for(int k = 2; k <= m; k++){
        for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++)
            sum[i][j] = (sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+f[k-1][i][j])%MOD;
        for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++)
            f[k][i][j] = (sum[i][n]-sum[i][j-1]+MOD)%MOD;
    }
    LL res = 0;
    for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++) res = (res+f[m][i][j])%MOD;
    cout << res << endl;
    return 0;
}

D. Minimax Problem

给一个的矩阵,任意取两行,对应数取\(max\),再对得到的数取\(min\),问得到的最大值可以由哪两行操作得到
最小化最大值问题,考虑二分答案,接下来变成判定可行性问题
假设当前二分值为\(x\)
由于\(m\le 8\),对于当前矩阵中的每一个数,大于等于\(x\)的为1,小于\(x\)的为0,这样每行可以用二进制来表示,现在问题转化为判断是否存在两行,使得其二进制表示取或为\((1<<m)-1\),用set或者map维护即可

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 3e5+7;
int n,m,mat[MAXN][10];
bool check(int mid){
    unordered_set<int> S;
    for(int i = 1; i <= n; i++){
        int msk = 0;
        for(int j = 1; j <= m; j++) if(mat[i][j]>=mid) msk|=(1<<(j-1));
        S.insert(msk);
        for(auto x : S) if((x|msk)==((1<<m)-1)) return true;
    }
    return false;
}
int main(){
    scanf("%d %d",&n,&m);
    int l = 0, r = 0;
    for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++){
        scanf("%d",&mat[i][j]);
        r = max(r,mat[i][j]);
    }
    while(l<=r){
        int mid = (l+r) >> 1;
        if(check(mid)) l = mid + 1;
        else r = mid - 1;
    }
    unordered_map<int,int> mp;
    for(int i = 1; i <= n; i++){
        int msk = 0;
        for(int j = 1; j <= m; j++) if(mat[i][j]>=r) msk|=(1<<(j-1));
        mp.insert(make_pair(msk,i));
        for(auto x : mp) if((x.first|msk)==((1<<m)-1)){
            cout << x.second << ' ' << i << endl;
            return 0;
        }
    }
    return 0;
}

E. Messenger Simulator

初始序列为\([1,2,3,...,n]\)现在有\(m\)次操作,每次操作把第\(x\)个数放到序列的最前面,问从开始到结束的过程中,每个数下标的最小值\(lmax[i]\)和最大值\(rmax[i]\)分别是多少
下标最小值:如果一个数\(i\)有被放到最前面过,那其下标最小值为\(1\),否则为\(i\)(只能被往后推)
下标最大值:分两部分来做。

  • 对于每个数\(i\),在它第一次被放到第一个位置之前,统计出现过不同的大于\(i\)的数\(dif\),更新\(rmax[i]\)为\(rmax[i]+dif\)。换一个角度,每个第一次出现的\(i\),可以对\([1,i-1]\)之间的每个数贡献\(1\),也就是区间加\(1\),更新的时候需要查询单点值,用树状数组维护即可
  • 对于每个数\(i\),当它被放到第一个位置之后,统计从当前操作到下一次\(i\)被放到第一个位置之前(如果没有下一次那就是到最后一次操作),出现过多少不同的数,记为dif,更新答案\(rmax[i] = max(rmax[i],1+dif)\),dif可以用主席树查询
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 3e5+7;
int n,m,lmax[MAXN],rmax[MAXN],A[MAXN];
vector<int> vec[MAXN];
bool vis[MAXN];
struct BinaryIndexedTree{
    int val[MAXN];
    inline int lowbit(int x){ return x & -x; }
    void update(int pos, int x){
        while(pos<=n){
            val[pos] += x;
            pos += lowbit(pos);
        }
    }
    int query(int pos){
        int res = 0;
        while(pos){
            res += val[pos];
            pos -= lowbit(pos);
        }
        return res;
    }
}BIT;
int last[MAXN];
struct PersistentSegmentTree{
    int root[MAXN],ls[MAXN<<6],rs[MAXN<<6],sz[MAXN<<6],tot;
    void update(int &now, int pre, int L, int R, int pos, int x){
        now = ++tot;
        sz[now] = sz[pre] + x;
        ls[now] = ls[pre]; rs[now] = rs[pre];
        if(L+1==R) return;
        int mid = (L+R) >> 1;
        if(pos<mid) update(ls[now],ls[pre],L,mid,pos,x);
        else update(rs[now],rs[pre],mid,R,pos,x);
    }
    int query(int L, int R, int rt, int pos){
        if(pos>=R) return 0;
        if(L>=pos) return sz[rt];
        int mid = (L+R) >> 1;
        return query(L,mid,ls[rt],pos) + query(mid,R,rs[rt],pos);
    }
}PST;
int main(){
    scanf("%d %d",&n,&m);
    for(int i = 1; i <= n; i++) lmax[i] = rmax[i] = i;
    for(int i = 1; i <= m; i++){
        scanf("%d",&A[i]);
        vec[A[i]].emplace_back(i);
        lmax[A[i]] = 1;
    }
    for(int i = 1; i <= m; i++){
        if(!last[A[i]]){
            PST.update(PST.root[i],PST.root[i-1],1,MAXN,i,1);
            last[A[i]] = i;
        }
        else{
            int tmp;
            PST.update(tmp,PST.root[i-1],1,MAXN,last[A[i]],-1);
            last[A[i]] = i;
            PST.update(PST.root[i],tmp,1,MAXN,last[A[i]],1);
        }
        if(vis[A[i]]) continue;
        vis[A[i]] = true;
        rmax[A[i]]+=BIT.query(A[i]);
        BIT.update(1,1);
        BIT.update(A[i],-1);
    }
    for(int i = 1; i <= n; i++) if(!vis[i]) rmax[i] += BIT.query(i);
    for(int i = 1; i <= n; i++){
        if(vec[i].empty()) continue;
        for(int j = 0; j < (int)vec[i].size(); j++){
            int pos = vec[i][j];
            int nxtpos = pos==vec[i].back()?m+1:vec[i][j+1];
            if(pos+1==nxtpos) continue;
            rmax[i] = max(rmax[i],1+PST.query(1,MAXN,PST.root[nxtpos-1],pos+1));
        }
    }
    for(int i = 1; i <= n; i++) cout << lmax[i] << ' ' << rmax[i] << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/kikokiko/p/12194809.html

时间: 2024-08-29 00:28:36

Educational Codeforces Round 80 (Rated for Div. 2)的相关文章

Educational Codeforces Round 80 (Rated for Div. 2)(C - Two Arrays )

C - Two Arrays 题目链接:https://codeforces.com/contest/1288/problem/C 题目: 题意:给你n,m,利用1~n之间的数(可重复)来组成长度为m的数组a,b,要求数组a非递减,数组b非递增,且a数组的数<=b数组中的数,求出a,b数组对数 思路:用动态规划,dp[i][j]是第i个位置放数字j的方案数,根据题意可以将b数组反置然后接在a后面,则该数组长度为2m,为一个非递减序列,则就是求1~n这些数字可重复组成多少种长度为2m的非递减序列,

Educational Codeforces Round 80 (Rated for Div. 2)参加感悟

这次比赛有14000+的人报名,结果我得了266名,创了新纪录. 进过这次比赛,我有回答了1800+. 寒假到了,又可以每次比赛都打了.平时进步很慢,我希望能在寒假有更大的进步. 作为寒假第一场比赛,发挥让我还是很满意的. 开始讲题: A: http://codeforces.com/contest/1288/problem/A 这题太水了,直接是sqrt(d)-1和sqrt(d),如果它们不行,那么其他的也肯定不行. 直接上代码: 1 #include<bits/stdc++.h> 2 #d

Educational Codeforces Round 80 (Rated for Div. 2(A Deadline )

(A) Deadline 题目: 思路:一开始还傻傻的暴力康康....只要求出令x=n的一半就行,然后判断 1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 //freopen("text","r",stdin); 6 int T; 7 scanf("%d",&T); 8 while(T--) 9 { 10 //cout<<cei

题解 Educational Codeforces Round 80 [Rated for Div. 2](CF1288)

前言:11点的时候某天下第一可爱的萌神问我怎么不打CF,跑去开题,11:30终于开了C和D,秒了一下,考后萌神轻松上分并告诉我E的tag于是我赛后补题. A:n/x上取整是(n-1)/x+1,式子变形成x+1+(n-1)/(x+1)<=d.根据a+b>=2√ab随便化简一下.(20s秒了??) 1 #include<stdio.h> 2 #include<math.h> 3 using namespace std; 4 int T,n,d,x,y; 5 int main

Educational Codeforces Round 80 (Rated for Div. 2) C - Two Arrays(DP)

???♀? ???♀? ???♀? 题意:从1~n里面选出来m个数字组成a数组,再选出来m个组成b数组,要求a非递减,b非递增,且bi>=ai 1,说是选两个数组其实就是选出来一个长m*2的非递减数组 2,假设要从n的全排列中选出来m长的非递减数组,因为元素是可重复的,最多重复m次,其实就是相当于从下面这个矩阵中选择元素 从这个矩阵中选择元素,每行只能选择一个,枚举我们选出的k个元素的最小值为[ i , j ]位置,那么除去这个元素选择k-1个元素的方案数之和就是k个元素,如图中红色标出位置,最

Educational Codeforces Round 80 (Rated for Div. 2)C(DP)

1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 const long long mod = 1e9+7; 5 long long pre[1007][1007],temp[1007][1007]; 6 int main(){ 7 ios::sync_with_stdio(false); 8 cin.tie(NULL); 9 cout.tie(NULL); 10 int n,m;

Educational Codeforces Round 80 (Rated for Div. 2)部分题解

A. Deadline 题目链接 题目大意 给你\(n,d\)两个数,问是否存在\(x\)使得\(x+\frac{d}{x+1}\leq n\),其中\(\frac{d}{x+1}\)向上取整. 解题思路 方案一:利用均值不等式公式推导 \(x+\frac{d}{x+1}=x+1+\frac{d}{x+1}-1\geq2\sqrt{d}-1\) 所以 \(\min(x+\frac{x}{d+1})=2\sqrt{d}-1\) 因此去判断\(2\sqrt{d}-1\leq n\)是否成,即\(4\

Educational Codeforces Round 80 (Rated for Div. 2)【A,B,C,D】C题DP{GG了} D题【数组转化成二进制形式判断+二分】

A题直接暴力水过 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 #define int long long 5 #define N 6666666 6 int arr[N]; 7 8 signed main(){ 9 int _;cin>>_; 10 while(_--){ 11 int n,m; 12 cin>>n>>m; 13 if(n>=m){ 14 cout<<"

Educational Codeforces Round 80 (Rated for Div. 2) 题解

Deadline Yet Another Meme Problem Two Arrays Minimax Problem Messenger Simulator Deadline \[ Time Limit: 2 s\quad Memory Limit: 256 MB \] 这是个对勾函数,所以最小的话是在 \(sqrt\) 位置,所以只要找这附近的数字就可以了. view /************************************************************