Codeforces Round #576 (Div. 2)

题目A

在这里插入图片描述
题意:输入n以及n个数,从n个数中找到一个一个数使得它前面至少有x个比它大的数,后面至少有Y个比它大的数。
思路;直接暴力枚举每个数,一定要注意数组+7越界的情况 呜呜呜 比赛过了重判的时候Wa在了第32组样例 枯了
代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#define Xiaobo main
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
const int INF=0x3f3f3f;
typedef long long ll;
int n,m;
int num[maxn];
int Xiaobo()
{
	int n,x,y;
	cin>>n>>x>>y;
	///memset(num,0x3f,sizeof(num));
	for(int i=0;i<n;i++) {
		cin>>num[i];
		//cout<<num[i]<<endl;
	}
	for(int i=0;i<n;i++) {
		int flag=1;
		for(int j=max(0,i-x);j<i;j++) {
			if(num[j]<num[i]) {
				flag=0;
				break;
			}
		}
		for(int j=i+1;j<=i+y&&j<n;j++) {
			if(num[j]<num[i]){
				flag=0;
				break;
			}
		}
		if(flag) {
			cout<<i+1<<endl;
			break; 
		} 
	}
   return 0;
}

B Water Lily

在这里插入图片描述
水题:给出了H、L让求水下部分的高度,因为莲花的总高度X和三角形斜边高度相同,所以列出方程直接AC (X-H)^2+ L^2= X^2
代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#define Xiaobo main
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
const int INF=0x3f3f3f;
typedef long long ll;
int n,m;
int num[maxn];
int Xiaobo()
{
	double xiebian,h,l;
	cin>>h>>l;
	xiebian=(h*h+l*l)/(2.0*h);
	printf("%.10f\n",xiebian-h);
   return 0;
}

C MP3

在这里插入图片描述
题意:
给定一个n和I然后输入n个数,有如下定义:记n个数中不相同个数为K 取k=⌈log2K⌉ 向上取整,k代表每个数所占的位,n个数总共占了nk个位然后I是字节,一个字节等于8个位,所以我们需要改变一些数使得这组数不相同的个数变小从而使nk<=I*8问最少需要改变多少个数
思路:
既然题目给出了I那我们就可以用 LL ans=1ll << min((l * 8 / n), 31);算出最多有多少个不相同的个数,然后用前缀和求连续相同的个数,最后再枚举左区间,区间的长度就是ans 然后从前缀和中找到具有最大相同个数的区间 最后用n减去即为最少需要改变的个数
代码1

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#include<map>
#define Xiaobo main
using namespace std;
const int maxn=4e5+5;
const int mod=1e9+7;
const int INF=0x3f3f3f;
typedef long long ll;
int n,m;
ll num[maxn];
ll sum[maxn];
map<ll,ll>mp;
int Xiaobo()
{
   int n,l;
   cin>>n>>l;
   ll cnt=0,cnt2=0;
   ll kn = 1ll << min((l * 8 / n), 31);//!!!注意和31比较大小防溢出
   for(int i=0;i<n;i++) {
   	    cin>>num[i];
   }
   sort(num,num+n);
   for(int i=0;i<n;i++) {
   		cnt2=1;
   	    while(num[i]==num[i+1]&&i<n) i++,cnt2++;//找相同的个数注意边界
   	    sum[cnt++]=cnt2;//前缀和
   }
   for(int i=0;i<cnt;i++) {
   	  if(i) sum[i]+=sum[i-1];
   }
   if(kn>=cnt) {
   	  cout<<"0\n";
   	  return 0;
   }
   ll ma=0;
   for(int i=0;i+kn<n;i++){
   	   ma=max(ma,sum[i+kn]-sum[i]);
   }
   cout<<n-ma<<endl;
   return 0;
}

代码2
思路:就是先排序 然后去重,统计每一个数字出现的次数然后求前缀和然后遍历每一个数字利用差分求最小 某位大佬的思路 哈哈 算是理解了 学会了一个函数unique(数组去重并不删除元素,而是把相邻元素相同的用其他元素覆盖掉,返回的是迭代器…STL里面的函数挺好用的 )和差分数组的应用 Orz~

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
 
typedef long long LL;
using namespace std;
 
int n, a[400005], I, num[400005], b[400005];
 
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
 
    scanf("%d %d", &n, &I);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]), b[i] = a[i];
    sort(b, b + n);
    sort(a, a + n);
    int pos = unique(b, b + n) - b;
    LL p = 1LL << min((I * 8 / n), 31);
    int cnt = 0;
    for (int i = 0; i < n; i++){
        num[cnt] = num[cnt - 1] + 1;
        int j = i + 1;
        for (; j < n; j++){
            if(a[j] != a[i]) break;
            num[cnt]++;
        }
        i = --j;
        cnt++;
    }
    int  ans = 0x3f3f3f3f;
    for (int i = 0; i < pos; i++){
        if(i + p - 1 >= pos) ans = min(ans, num[i - 1]);
        else ans = min(ans, num[pos - 1] - num[i + p - 1] + num[i - 1]);
    }
    cout << ans << endl;
 
    return 0;
}

D Welfare State

在这里插入图片描述
题意
输入一个n和n组数,一个q代表q次访问,接下来输入一个操作数,如果是1 后面有个p x 需要把第p个数修改为x 如果是2 接下来有个x 需要把数组中比x小的元素变成x
思路:
一种思路是线段树 ,维护就完事了,,,另外一种思路特别巧妙记最初的数组为a[]记录原来的数据,记另外一个数组b[]如果有操作2的话记录修改值得下标,一个c[]数组用来存1操作,既然一共有Q次操作,那么我们想一下,假设第一次输出5第二次输入3第三次再输入5那么中间的3还有意义吗?换句话说我们记录下Q次改变的值,然后从后到前依次更新就好了,最后输出数组元素的时候还有一种情况,如果我先在让操作2之前进行了1操作修改了原来的值,那么就需要比较操作1修改的值和操作2之后的值 输出大的即可,同理如果在操作2之后修改了原来的值,直接输出这个时候的值就好了,当然如果后面没了操作2的话那么取两者之间的最大值仍然成立,这个思路挺巧妙的,但是不太好理解,相当于先把操作数记录下来,然后最后再比较输出,线段树不太会写,呜呜呜,稳定掉分了~~~看代码吧
首先是线段树的

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,q;
int a[maxn],b[maxn],last[maxn],A[maxn],O[maxn];;
bool vis[maxn];
map<int,int>m;
struct tree{
    int l,r;
    int Max;
}st[maxn*4];
void build(int l,int r,int i){
    st[i].l=l;
    st[i].r=r;
    if(l==r){
        st[i].Max=b[l];
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,i*2);
    build(mid+1,r,i*2+1);
    st[i].Max=max(st[i*2].Max,st[i*2+1].Max);
}
int query(int l,int r,int i){
    if(l<=st[i].l&&r>=st[i].r)
        return st[i].Max;
    int mid=(st[i].l+st[i].r)/2;
    int ans=0;
    if(l<=mid)ans=max(ans,query(l,r,i*2));
    if(r>mid)ans=max(ans,query(l,r,i*2+1));
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    scanf("%d",&q);
    int op,cnt=0;
    int u,val;
    int mmax=0;
    for(int i=1;i<=q;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d",&u,&val);
            if(m.find(u)==m.end()){
                m[u]=++cnt;
                vis[u]=1;
                last[cnt]=val;
                O[u]=i;
            }
            else{
                vis[u]=1;
                last[m[u]]=val;
                O[u]=i;
            }
        }
        else if(op==2){
            int x;
            scanf("%d",&x);
            b[i]=x;
            mmax=max(mmax,x);
        }
    }
    build(1,q,1);
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            if(mmax>a[i])A[i]=mmax;
            else A[i]=a[i];
        }
        else{
            int fin=last[m[i]];
            int temp=query(O[i],q,1);
            if(temp>fin)A[i]=temp;
            else A[i]=fin;
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d%c",A[i],i==n?'\n':' ');

然后是另外一个思路的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<cmath>
#define Xiaobo main
using namespace std;
const int maxn=2000050;
const int mod=1e9+7;
const int INF=0x3f3f3f;
typedef long long ll;
int n,m;
int num[maxn];
int a[maxn],b[maxn],c[maxn]; 
int Xiaobo()
{
   cin>>n;
   for(int i=0;i<n;i++) {
   	  cin>>num[i];
   }
   cin>>m;
   for(int i=0;i<m;i++) {
   		int k;
   		cin>>k;
   		if(k==1) {
   			int p,q;
   			cin>>p>>q; 
   		   //记录下要修改的值和下标
   		   num[p-1]=q;
   		   b[p-1]=i;
		}
		else {
		   cin>>c[i];
		} 
   }
   for(int i=m;i>=0;i--) {
   	   c[i]=max(c[i],c[i+1]);
   }
   for(int i=0;i<n;i++ ) {
   	   cout<<max(num[i],c[b[i]])<<" "; // 想一下为啥是b[i]而不是b[i]-1
   }
   return 0;
}

总结: 思路有待提升,线段树、差分数组也要抓紧学习了…注意赛后总结,差的太多了 呜呜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值