I. Left Shifting

题目链接👈

题目描述🥰

题目思路😀

简单模拟即可

AC代码🧠

void solve()
{
	string s;
	cin>>s;
	int n=s.size();
	if(s[0]==s[n-1]){
		cout<<0<<endl;
		return;
	}
	for(int i=0;i<n-1;i++)if(s[i]==s[i+1]){
		cout<<i+1<<endl;
		return;
	}
	if(s[0]!=s[n-1]){
		cout<<-1<<endl;
	}
}

A. Printer

题目链接👈

题目描述🥰

题目思路😀

这个题目是简单的题目,但是坑也是真的多,vp的时候贡献了好几发罚时😰。

思路就是一个简单的二分,对时间进行二分即可。

坑1:数据的溢出

我们在check函数的过程中可能会有数据的溢出,所以我们需要过程中已经满足返回条件就可以直接返回即可,不要等到最后才返回,这样就能有效的避免过程中的数据溢出(贡献了7发罚时才找出的错误😅)

坑2:二分的答案范围

这个题目也是特殊到极致了,二分的最大值如果取1e18并不能满足答案的范围🤯,要开2e18才能过💩(第一次见😭)

AC代码🧠

void solve()
{
	int n,k;
	cin>>n>>k;
	vector<edge>a(n);
	for(int i=0;i<n;i++){
		cin>>a[i].t>>a[i].l>>a[i].w;
	}
	int l=1,r=2e18;
	auto check=[&](int mid)->bool{
		int res=0;
		for(int i=0;i<n;i++)
		{
		        int sum=a[i].t*a[i].l+a[i].w;
		    	int cnt=mid/sum;
		    	res+=cnt*a[i].l+min((mid%sum)/a[i].t,a[i].l);
		    	if(res>=k)return true;
		}
		return res>=k;
	};
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
}

K. Matrix

题目链接👈

题目描述🥰

题目思路😀

一个比较简单的构造题目,构造思路首先把不同的四个数字填到左上角,然后向左向下进行拓展

举一个n=5的例子来看,我们就可以和下面一样填

Question:如何满足一定出现了元素1~2*n呢?

除了左上角的4个元素,横向有n-2种元素,纵向有n-2种元素,再加上左上角的四种元素,就等于2*n种元素

AC代码🧠

这个代码的判断no的代码纯属多余😂

const int N=55;
int g[N][N];
void solve()
{
	int n;
	cin>>n;
	g[1][1]=1;
	g[1][2]=2;
	g[2][1]=3;
	g[2][2]=4;
	int cnt=5;
	for(int j=3;j<=n;j++)
	{
		g[1][j]=cnt;
		g[2][j]=cnt;
		cnt++;
	}
	for(int i=3;i<=n;i++)
	{
	 for(int j=1;j<=n;j++)
	  {
	  	 g[i][j]=cnt;
	  }
	  cnt++;
	}
	  map<int,int>hash;
	  for(int i=1;i<=n;i++)
	{
	 for(int j=1;j<=n;j++)
	 {
	    hash[g[i][j]]++;
	 }
	 }
	 if(hash.size()<2*n){
	 	cout<<"No"<<endl;
	 	return;
	 }
	  cout<<"Yes"<<endl;
	for(int i=1;i<=n;i++)
	{
	 for(int j=1;j<=n;j++)
	 {
	 	cout<<g[i][j]<<" ";
	 }
	 cout<<endl;
	 }
}

 C. Colorful Segments 2

题目链接👈

题目描述🥰

题目思路😀

我们需要计算和每一个线段重叠的线段个数ai,答案就是(k-a1)*(k-a2)*(k-a3)...*(k-an)

那么为什么呢?

因为我的每一个线段的涂色只需要和重叠线段的涂色不一样即可,所以就有(k-ai)种可能,根据乘法原理答案就是(k-a1)*(k-a2)*(k-a3)...*(k-an)

但是注意代码实现不要偏了,不要使用双指针来求和每一个线段重叠的线段个数ai,  理由见下图

我们双指针的计算在遍历到ai的时候,会找到第一个和ai重叠的区间aj,所以会误认为把两者之间的线段都视为重叠,而其实不是的,如上图,虽然1和3重叠,但是1和3直接的2并不和3重叠,所以双指针的实现思路会有问题

而正确思路就是我们需要用一个小根堆来记录之前的区间的右端点,保证当前的区间的左端点小于堆顶元素后,这样就可以保证堆里面的区间都是和当前区间重合的。

AC代码🧠

struct edge{
	int l;
	int r;
	bool operator<(const edge& b)const
	{
		if(l==b.l)return r<b.r;
		return l<b.l;
	}
};
void solve()
{
	int n,k;
	cin>>n>>k;
	vector<edge>a(n);
	for(int i=0;i<n;i++)
	{
		cin>>a[i].l>>a[i].r;
	}
	sort(a.begin(),a.end());
	int ans=1LL;
	priority_queue<int,vector<int>,greater<int>>q;
	for(int i=0;i<n;i++)
	{
		// while(j<i&&a[i].l>a[j].r)j++;
		while(q.size()&&q.top()<a[i].l)q.pop();
		ans=ans*(k-q.size())%MOD;
		q.push(a[i].r);
	}
	cout<<ans<<endl;
}

F. Divide the Sequence

题目链接👈

题目描述🥰

题目思路😀

vp的时候是队友写出来的,但是赛后补题的时候我自己看了很久😇

这个题目让我觉得最妙的思路就是在于把乘法化成加法,题目要求的是i*si,你可以把这个视为si被加了i遍,那么题目就会清晰很多了

我们需要求的是把数组分成k份的时候的最大值,我们可以从1开始看起,如果数组被分成1份,那么最大值就是sum本身。如果被分成2份,就相当于某一个后缀会再加一次,为了最大化,那么我们肯定加最大的那个后缀,后面分成3份也是同样的道理。

因为题目中的n是5e5,所以我们需要先预处理后缀和并排序,分成k份,答案就是前k-1大的后缀相加+sum。

AC代码🧠

void solve()
{
	int n;
  cin >> n;
  vector<int> a(n+1);
  int sum=0;
  for (int i = 1; i <=n; ++i) cin >> a[i],sum+=a[i];
  vector<int>pre(n+2,0);
  //预处理后缀和
  for(int i=n;i>=1;i--)pre[i]=pre[i+1]+a[i];
  //把2~n的后缀和从大到小进行排列
  sort(pre.begin()+2,pre.begin()+n+1,greater<int>());
  vector<int>ans(n+1);
  ans[1]=sum;
  for(int i=2;i<=n;i++)ans[i]=ans[i-1]+pre[i];
  for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
  cout<<endl;
}

J. Colorful Spanning Tree

题目链接👈

题目描述🥰

题目思路😀

我们要保证权重最小,那么我们的每一个颜色可以留一个和其他颜色来连通,其他都和连接代价最小的颜色进行连接即可,最后把剩下的每一个颜色跑一个最小生成树算法即可。

AC代码🧠

void solve() {
  int n;
  cin >> n;
  vector<int> a(n);
  for (int i = 0; i < n; i++) cin >> a[i];
  int ans = 0;
  vector<vector<int>> g(n, vector<int>(n));
  for (int i = 0; i < n; i++) {
    int res = 1e9;
    for (int j = 0; j < n; j++) {
      cin >> g[i][j];
      res = min(g[i][j], res);
    }
    ans += res * (a[i] - 1);
  }
  // prim
  vector<int> dis(n, 1e9);
  vector<int> vis(n, 0);
  dis[0] = 0;
  for (int i = 0; i < n; i++) {
    int u = -1;
    for (int j = 0; j < n; j++) {
      if (!vis[j] && (u == -1 || dis[j] < dis[u])) u = j;
    }
    vis[u] = 1;
    ans += dis[u];
    for (int k = 0; k < n; k++) {
      dis[k] = min(dis[k], g[u][k]);
    }
  }
  cout << ans << endl;
}

 

 posted on 2025-03-31 18:00  熙玺  阅读(51)  评论(0)    收藏  举报

Shu-How Zの小窝

Loading...