刷题记录 CF每日一题打卡 2020.5月26-6月2

1.CF1198A MP3

题意有点绕
总需要的存储空间为nlog2tn*\log_{2} ttt为不同音量的数量

现有的存储空间为 m8m*8

要选择一个区间使所有的的音量值都变为区间之内,使之可以储存下来,最小的被更改的强度值的数量

先排序,并求出tt和每一个音量的数量,m8m*8

可以得出 log2tmn\log_{2} t\leq\frac{m}{n},我们需要找到一个符合条件的tt又要使被更改的强度值的数量最小,要怎么办呢?用双指针,让不同音量数量在maxxmaxx范围内,并且记录最多同时有多少个音量在队列中,最终答案即为nansn-ans

#include<bits/stdc++.h>
using namespace std;
int n,m,k,ans,c,maxx;
void fuck();
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
int a[400005],b[400005];
bool cmp(int x,int y){
	return x>y;
}
vector<int>v;
signed main(){
	cin>>n>>m;
	m*=8;
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	sort(a+1,a+1+n,cmp);
	int num=0;
	int t=1;
	for(int i=1;i<=n;i++){
		if(a[i]!=a[i-1]){
			num++;
			b[t]=num;
			t++;
			num=0;
		}
		else num++;
	}
	maxx=m/n;
	if(log2(t)<=maxx){
		cout<<"0";
		return 0;
	}
	maxx=pow(2,maxx);
//	for(int i=1;i<=t+maxx;i++){
//		b[i]+=b[i-1];
//	}
	ans=0;
	queue<int>q;
	for(int i=1;i<=t;i++){
		q.push(b[i]);
		c+=b[i];
		if(q.size()>maxx){
			int x=q.front();
			c-=x;
			q.pop();
		}
		ans=max(ans,c);
	}
	cout<<n-ans;
}

2.CF486C Palindrome Transformation

有四种操作,光标左移,右移,将光标所在的字母++ or - -

问最少要多少次操作能使其变为回文串

直接贪心,记录下最左端需要修改的字母和最右端需要修改的字母

讨论一下这样的正确性,从下标00开始遍历,达到的第一个需要改的即为ll,最后一个修改的位置为rr,最终光标移动的总次数为

ans+=min(abs(p-r),abs(p-l));
ans+=max(r-l,0);

模拟一下就能明白是什么意思

例如光标初始位置为p=5p=5ll为2,rr为7,先加上757-5,即为到r的距离,但是光标总是需要从l走到r这个位置的,所以需要加上rlr-l

对应位置的字母的改法就比较简单了
完整代码:

#include<bits/stdc++.h>
using namespace std;
string a;
int n,p,l=-1,r;
int main(){
	cin>>n>>p;
	cin>>a;
	n--;
	p--;
	long long ans=0;
	if(p>n/2)p=n-p;
	for(int i=0;i<=n/2;i++){
		if(a[i]!=a[n-i]){
			int s=abs(a[i]-a[n-i]);
			ans+=min(s,26-s);
			if(l<0)l=i;
			else r=i;
		}
	}
	ans+=min(abs(p-r),abs(p-l));
	ans+=max(r-l,0);
	if(l<0)cout<<"0";
	else cout<<ans;
}

3.CF467C George and Job

n个数,选出k组,每组m个数,使选出的数的和值最大

先求出前缀和

dp[i][j]dp[i][j]代表前ii个数选jj个区间可以获得的最大值

转移方程:dp[i][j]=max(dp[i][j],dp[im][j1]+sum[i]sum[im]);dp[i][j]=max(dp[i][j],dp[i-m][j-1]+sum[i]-sum[i-m]);

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
int n,m,k;
int a[5005],sum[5005],dp[5005][5005];
signed main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		a[i]=read();
		sum[i]=a[i];
	}
	for(int i=1;i<=n;i++){
		sum[i]+=sum[i-1];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			dp[i][j]=dp[i-1][j];
			if(i>=m){
				dp[i][j]=max(dp[i][j],dp[i-m][j-1]+sum[i]-sum[i-m]);
			}
		}
	}
	cout<<dp[n][k];
	return 0;
}

4.CF1228C Primes and Multiplication

数论,咕咕咕

5.CF1279C Stack of Presents

放回来的时候可以任意顺序,维护最大深度即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int tt,n,m,a[maxn],b[maxn],num[maxn];
int main(){
	cin>>tt;
	while(tt--){
		long long ans=0;
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			int x;
			cin>>x;
			a[x]=i;
		}
		int dep=0;
		for(int i=1;i<=m;i++){
			int x;
			cin>>x;
			if(a[x]>dep){
				ans+=(a[x]-i)*2+1;
				dep=a[x];
			}
			else ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

6.CF1238C Standard Free2play

给出nn个已经选中的台阶

初始时有 nn 个平台为被选中,保证平台 hh 被选中,您每次可以进行一个操作,不妨假设您当前站在平台 xx 处(此时平台 xx 一定被选中),即让平台 xx变成未被选中,而平台 x1x - 1变成相反的状态。

如果落差大于1,不管这个数字是多少都是一样的,需要一个魔法水晶

比如选中在1000,999和1是打开的,关闭1000的时候999也会关闭,用水晶关闭999这一层才能到达999,然后关闭999,998变为打开状态,关闭998,997又变成打开......

#include<bits/stdc++.h>
using namespace std;
int t,h,n,a[200005];
int main(){
	cin>>t;
	while(t--){
		cin>>h>>n;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		int ans=0;
		a[n+1]=0;
		for(int i=2;i<=n+1;i++){
			if(a[i]-a[i+1]>1)ans++;
			else i++;
			
		}
		cout<<ans<<endl;
	}
	return 0;
}

7.CF1223C Save the Nature

咕了,待补

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章