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

C D E 这三道题感觉挺好

决定程序是否能通过优化在要求的时间内完成,程序运行时间为t,你可以选择花X天来优化,优化后程序的运行时间为t/(x+1)取上整,花费的时间为程序运行时间加上优化时间

如果程序运行时间小于等于要求时间,那就不需要优化,否则必须优化,假设优化X天,那么总时间就是X+t/(X+1) ,我们的目标事求他的最小值,根据均值不等式

另外均值不等式中等于号成立的条件是x1=x2=....xn

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e4+5;
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,d;
		scanf("%d%d",&n,&d);
		if(d<=n) puts("YES");
		else {
			int x=sqrt(d);
			int ans=min(ceil(1.0*d/x)+x,ceil(1.0*d/(x+1))+(x+1));
			if(ans<=n+1) puts("YES");
			else puts("NO");
		}
	} 

}
 

 

对式子进行化简即可发现规律 ,偷懒直接贴官方的题解

#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
int main(){
	int T;
	cin>>T;
	while(T--){
		int a,b;
		cin>>a>>b;
		ll now=9,cnt=0;
		while(now<=b){
			now=now*10+9;
			cnt++;
		}
		cout<<1ll*a*cnt<<endl;
	}
}
 

  

两种方法,都需要发现一个性质就是一个长度为2*m的非递减序列仅能构造出一个解

所以这道题本质上是找到使用1-n能凑出多少个不同的非递减序列,并且不能重复

法一: 

法二:问题等价于1-n中每一个数有无限个,从中挑出2*m个元素组成一个集合,有多少种选法,答案是

#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const ll P=1e9+7;
ll jc[1100],inv[1100];
ll qpow(ll a,int n){
	ll ans=1;
	for(;n;n>>=1,a=a*a%P)
		if(n&1) ans=ans*a%P;
	return ans;
}
int main(){
	jc[0]=1;
	for(int i=1;i<=1050;i++){
		jc[i]=jc[i-1]*i%P;
		inv[i]=qpow(jc[i],P-2);
	}
	inv[0]=1;
	int n,m;
	cin>>n>>m;
	cout<<jc[n+2*m-1]*inv[2*m]%P*inv[n-1]%P<<endl;
}
 

  

先贴一波官方题解

先二分答案,然后将矩阵的每一行压缩成一个m位的二进制 数(如果比X小就赋值为0,否则赋值为1)这样问题就转化为了是否存在两个数异或值为2^m-1

由于n比较大,不能n^2,但是发现可能的二进制数很少,所以我们可以用将可能的二进制数存下来,然后去枚举这些二进制数,复杂度不高了

#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int dim1=3e5+5;
const int dim2=8;
int a[dim1][dim2];
int n,m;
int ans_l,ans_r;
bool check(int x){
	vector<int> mask(1<<m,-1);
	for(int i=0;i<n;i++){
		int now=0;
		for(int j=0;j<m;j++){
			if(a[i][j]>=x) now^=1<<j;
		}
		mask[now]=i;
	}
	for(int m1=0;m1<1<<m;m1++){
		for(int m2=0;m2<1<<m;m2++){
			if(mask[m1]!=-1 && mask[m2]!=-1 && (m1|m2)==(1<<m)-1) {
				ans_l=mask[m1],ans_r=mask[m2];
				return 1;
			}
		}
	}
	return false;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			scanf("%d",&a[i][j]);
	int l=1,r=1e9;
	while(l<r){
		int mid=(l+r+1)/2;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	check(l);
	printf("%d %d\n",ans_l+1,ans_r+1);

}
 

  

法一 好想但是代码比较复杂

最小值很容易确定,出现过就是1,否则就是其初始位置

对于每一个数来说,他的最大值有两种情况,第一种是他第一次到达队首之前的位置是哪里,这个等价于计数他前面有多少个数比他大,树状数组来解决

第二个就是相邻两次到达队首的时刻,这个就是就是计数两次之间有多少个不同的数,这个用莫队来完成

法二:模拟移动过程,但是需要将队列逆序,这样避免的移动,插入队首的操作可以看做是队尾增加一个数

插入的同时计算并更新最大值

说的比较粗略,具体看官方题解

法一 树状数组+莫队

#include<bits/stdc++.h>

#define X first
#define Y second 

using namespace std;

const int N=3e5+5;
const int tk=550;

typedef pair<int,int> pi;
typedef long long ll;

int cnt[N],tot;

vector<int> pos[N];

int a[N];

void add(int x){
	++cnt[x];
	if (cnt[x] == 1) ++tot;
}

void rem(int x){
	if (cnt[x] == 1) --tot;
	--cnt[x];
}

int f[N];

void upd(int x){
	for (int i = x; i >= 0; i = (i & (i + 1)) - 1)
		++f[i];
}

int get(int x){
	int res = 0;
	for (int i = x; i < N; i |= i + 1)
		res += f[i];
	return res;
}

int main(){
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++){
		scanf("%d",&a[i]);
		--a[i];
	}
	for(int i=0;i<m;i++){
		pos[a[i]].push_back(i);
	}
	vector<pi> qr;
	for(int i=0;i<n;i++){
		for(int j=1;j<pos[i].size();j++){
			qr.push_back(make_pair(pos[i][j-1]+1,pos[i][j]-1));
		}
		if(!pos[i].empty()) qr.push_back(make_pair(pos[i].back()+1,m-1));
	}

	sort(qr.begin(),qr.end(),[](pi x,pi y){
		if(x.X/tk!=y.X/tk) return x.X<y.X;
		if((x.X/tk)&1) return x.Y<y.Y;
		return x.Y>y.Y;
	});
	vector<pi> ans(n);
	for(int i=0;i<n;i++)
		ans[i]={i,i};
	for(int i=0;i<m;i++)
		ans[a[i]].X=0;
	int L=0,R=-1;
	for(int i=0;i<(int)qr.size();i++){
		int l=qr[i].X,r=qr[i].Y;
		if(l>r) continue;
		int x=a[qr[i].X-1];
		while(L<l) rem(a[L++]);
		while(L>l) add(a[--L]);
		while(R>r) rem(a[R--]);
		while(R<r) add(a[++R]);
		ans[x].Y=max(ans[x].Y,tot);
	}
	for(int i=0;i<m;i++){
		if(i==pos[a[i]][0]) {
			ans[a[i]].Y=max(ans[a[i]].Y,a[i]+get(a[i]));
			upd(a[i]);
		}
	}
	for(int i=0;i<n;i++){
		if(pos[i].empty()){
			ans[i].Y=max(ans[i].Y,i+get(i));
		}
	}
	for(int i=0;i<n;i++){
		printf("%d %d\n",ans[i].X+1,ans[i].Y+1);
	}
}

法2 树状数组

#include<bits/stdc++.h>

using namespace std;

const int maxn=6e5+5;

int f[maxn];

void upd(int x,int val){
	for(int i=x;i>=0;i=(i&(i+1))-1)
		f[i]+=val;
}

int get(int x){
	int res=0;
	for(int i=x;i<maxn;i|=i+1)
		res+=f[i];
	return res;
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	vector<int> mi(n);
	iota(mi.begin(),mi.end(),0);
	vector<int> mx=mi;
	vector<int> a(m);
	for(int i=0;i<m;i++)
		scanf("%d",&a[i]),--a[i],mi[a[i]]=0;
	vector<int> pos(n);
	for(int i=0;i<n;i++)
		pos[i]=n-i-1;
	for(int i=0;i<n;i++)
		upd(i,1);
	for(int i=0;i<m;i++){
		mx[a[i]]=max(mx[a[i]],get(pos[a[i]]+1));
		upd(pos[a[i]],-1);
		pos[a[i]]=i+n;
		upd(pos[a[i]],1);
	}
	for(int i=0;i<n;i++)
		mx[i]=max(mx[i],get(pos[i]+1));
	for(int i=0;i<n;i++)
		printf("%d %d\n",mi[i]+1,mx[i]+1);
	return 0;
}
 

  

原文地址:https://www.cnblogs.com/033000-/p/12210668.html

时间: 2024-08-30 13:27:06

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

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

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 /************************************************************