当先锋百科网

首页 1 2 3 4 5 6 7

好久没有写博客了,回来热热手顺便找找感觉(gugugu)
这次因为下午刚打完训练赛又恰巧打的成绩不好,所以基本上没出几题(又掉了一波分),只能现在补补题了。
A. Ilya and a Colorful Walk
题目大概就是说从最大的两个不同颜色的距离是多少。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define mm(i,v) memset(i,v,sizeof i);
using namespace std;
typedef long long ll;
const int maxn=300000+10;
int a[maxn];
int main()
{
	int x,n,y;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	if(a[0]!=a[n-1]){
			printf("%d\n",n-1);
			return 0;
		}
	for(int i=1;i<n;i++){
		if(a[i]!=a[i-1]){
			x=n-i-1;
			break;
		}
	} 
	for(int i=n-2;i>=0;i--){
		if(a[i]!=a[i+1]){
			y=i;
			break;
		}
	}
	int maxx=max(x,y);
	printf("%d",maxx);
	return 0;
}

B. Alyona and a Narrow Fridge

大概就是一个h×2的冰箱,给你一堆瓶子,让你按顺序放,求最多能放几瓶。
考虑贪心的做法,每次最大的次大并排放才能保证放的最多,所以我们只需要枚举放几个就行了,时间复杂度 n×n×log.

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define mm(i,v) memset(i,v,sizeof i);
using namespace std;
typedef long long ll;
int n,h;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>h;
	vector<int> a(n);
	for(int i=0;i<n;i++)
		cin>>a[i];
	for(int k=n;k>=0;k--){
		vector<int>	b(a.begin(),a.begin()+k);
		sort(b.begin(),b.end());
		ll sum=0;
		for(int i=(int)b.size()-1;i>=0;i-=2)
			sum+=b[i];
		if(sum<=h){
			cout<<k<<"\n";
			return 0;
		}
	}
	return 0;
}

C. Ramesses and Corner Inversion
题意:每次只能变换最少2*2的矩阵的四角,0变1,1变0,然后问给出两个矩阵能不能通过上述变换变得相等。
思路:每次贪心的变换最小的矩阵,也就是2 * 2如果发现这种变换到最会一行或一列出现不等,因为最后一行或一列无法再进行2 * 2的变换了,也就证明不能。否则,就证明可以通过上述变换使两矩阵相等。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define mm(i,v) memset(i,v,sizeof i);
using namespace std;
typedef long long ll;
//const int maxn=505;
//int a[maxn][maxn],b[maxn][maxn];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin>>n>>m;
	vector<vector<int> > a(n,vector<int>(m));
	vector<vector<int> > b(n,vector<int>(m));
	for(int i=0; i<n; i++)
		for(int j=0; j<m; j++)
			cin>>a[i][j];
	for(int i=0; i<n; i++)
		for(int j=0; j<m; j++)
			cin>>b[i][j];
	for(int i=0; i<n; i++) {
		for(int j=0; j<m; j++) {
			if(a[i][j]!=b[i][j]) {
				if(i==n-1||j==m-1) {
					cout<<"No"<<'\n';
			 		return 0;
				}
				a[i][j]^=1;
				a[i+1][j]^=1;
				a[i][j+1]^=1;
				a[i+1][j+1]^=1;
			}
		}
	}
	cout<<"Yes"<<'\n';
	return 0;
}

D. Frets On Fire
首先这题要先理解离散化的知识,不懂的小伙伴请戳这里
接下来就是题意,就是求一个数矩阵,给你了每行的开头,让你求出每个段内有多少个不同的数。
注意到数据达到10^18,所以肯定是要离散化的。
具体思路就是
现在,我们可以把每一行看作一个 [s[i],s[i]+r-l] 的闭区间,于是我们把这n个闭区间放到数轴上,如果没有重合,那么答案就是n*(r-l+1)了,但显然区间重合是可能存在的。最暴力的想法就是初始化一个mark[值域]数组,对每一个区间里的数字逐个mark上,最后再遍历值域。然而这玩意儿一次询问就是O(n*值域),显然不行。

这时我们观察数轴上的这n个闭区间,发现他们无论何时(每组询问)的长度都是一致的,因此我们可以把这些区间分成两类:如果对于一个区间I = [xi,yi], 存在区间J = [xj,yj], 使得xj <= yi,我们说区间I是”贡献确定“的,因为由于区间长度一致,区间I在yi之后的数字都可以由区间J所替代,所以此时区间I的贡献确定为yi-xi。相反地,如果不存在这样的区间J,那么区间I就是”贡献不确定“的,他的贡献与区间长度有关(其实就是长度+1,闭区间嘛)。
在这里插入图片描述

回到这道题,每个询问等价的那个参数(记作q[k], q[k] = rk-lk),本质上就是那个区间长度,所以我们知道对于每个”贡献不确定“的区间,他的贡献是q[k] + 1。那对于”贡献确定“的区间。。。废话他们的贡献都确定了好吗。那这个确定的贡献是多少呢,我们可以把这n个区间排个序,排好序之后第i个区间的确定贡献(也就是最大的贡献,记作t[i])就是 t[i] = s[i+1] - s[i] , 也就是他和下一个区间开头的距离了。最后,判断一个区间是否确定贡献的方式就是判断t[i] 与 q[k] 的大小关系,如果t[i] <= q[k], 那么他的区间尾就碰到了下一个区间头,贡献就确定为t[i]了。我们可以将 t[i] 排序,二分查找有多少个区间为确定贡献的。

那么,对于每一个询问 q[k], 覆盖的数字的个数 ans[k] = Σpi=1t[i] + (n-p) * (rk-lk+1), 其中p代表有且仅有前p小的t[i] 小于q[k]。需要前缀和数组sum[p]记录前p个t[i] 的和。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define mm(i,v) memset(i,v,sizeof i);
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n,q; 
ll s[maxn],t[maxn];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>s[i];
	sort(s,s+n);
	for(int i=0;i<n-1;i++)
		s[i]=s[i+1]-s[i];
	sort(s,s+n-1);
	for(int i=n-1;i>=1;i--)
		s[i]=s[i-1];
	s[0]=0;
	for(int i=1;i<n;i++)
		t[i]=t[i-1]+(s[i]-s[i-1])*(n-i+1);
	cin>>q;
	for(int i=0;i<q;i++){
		ll l,r;
		cin>>l>>r;
		l=r-l+1;
		int temp=lower_bound(s,s+n,l)-s-1;
		cout<<t[temp]+(l-s[temp])*(n-temp);
		if(i!=n-1)
			cout<<" ";
		else
			cout<<"\n";
	}
	return 0;
}

E. Pavel and Triangles
题意:给你一个数,代表从2^0 到 2n次方的每个木棍数。让你来匹配三角形,求最多匹配的三角形数量。
题解:优先匹配小的,最后把剩下的一个跟别两个一样的匹配。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define mm(i,v) memset(i,v,sizeof i);
using namespace std;
typedef long long ll;
const int maxn=3e5+10;

int a[maxn];
ll ans;
int n,t,res;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int j;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		j=min(a[i]>>1,t);
		a[i]-=(j<<1);
		t-=j;
		ans+=j;
		ans+=(a[i]/3);
		a[i]%=3;
		t+=a[i];
	}
	cout<<ans;
	return 0;
}