第三场(J待补)

Fillomino 2
题意:给n*n的方格,主要看左下部分,输入整数n,n个整数a[i],表示(i,i)位置上的数字,要求划分出一个连通块,块内的元素个数恰为对角线上的数字。
思路:贪心,对于每次扩展首先往左扩,行不通往下扩,最后往右扩。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cctype>
#define debug(x) cout<<#x<<"="<<x<<'\n';
#define int long long
#define eb emplace_back
#define endl '\n'
#define per(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
int a[510][510]={0},b[510][510]={0};
int T,n,m,k,ans;
void dfs(int x,int y,int k)
{
	if(b[k][k]==1)return ;
	if((y-1)>=1&&!a[x][y-1])
	{
		a[x][y-1]=a[k][k];
		b[k][k]--;
		dfs(x,y-1,k);
	}
	else if(x+1<=n&&!a[x+1][y])
	{
		a[x+1][y]=a[k][k];
		b[k][k]--;
		dfs(x+1,y,k);
	}
	else
	{
		a[x][y+1]=a[k][k];
		b[k][k]--;
		dfs(x,y+1,k);
	}
}
void solve()
{
	cin>>n;
	per(i,1,n)cin>>a[i][i],b[i][i]=a[i][i];
	per(i,1,n)dfs(i,i,i);
	per(i,1,n)
	{
		per(j,1,i)
		cout<<a[i][j]<<' ';
		cout<<endl;
	}
		
}
signed main()
{
//	cin>>T;
//	while(T--)
	 solve();
}
 

B. AGAGA XOOORRR
题意:n个数字,询问是否能通过任意次数,任取两个数进行按位与,并将该结果放入数组,最后使数字剩下最少两个相同的数字。
思路:倒着看,根据按位与的性质,大致可分为两种情况,一是最后的结果有偶数个相同的数,此时所有数按位与为0。二是最后结果有奇数个相同的数字,此时所有数的按位与为设x,在重新按位与,如果此时结果等于x,cnt++。按位与结果置为0继续进行操作。最后查看cnt是否>=3即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cctype>
#define debug(x) cout<<#x<<"="<<x<<'\n';
#define int long long
#define eb emplace_back
#define endl '\n'
#define per(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
int a[2010];
int T,n,m,k,ans;

void solve()
{
	int ans1=0,ans=0;
	cin>>n;
	per(i,1,n)
	{
		cin>>a[i];
		ans^=a[i];
	}
	if(ans==0)
	{
		cout<<"YES"<<endl;
		return ;
	}
	int cnt=0;
	per(i,1,n)
	{
		ans1^=a[i];
		if(ans1==ans)
		{
			ans1=0;
			cnt++;
		}
	}
	if(cnt>=3)cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	 solve();
}
 

C. Phoenix and Socks
题意:共有n只袜子,l只左袜子,r只右袜子,下一行n个数a[i]代表袜子的颜色。
可以进行以下操作:1、将左袜子变为右袜子2、将袜子的颜色进行更改。每次操作操作次数+1,问能组成n/2双袜子的最小操作数。
思路:首先消除颜色相同的左右袜子,此时操作数无变化。之后尝试将颜色相同,左右也相同的袜子变化方向,此时操作时加1,最后将剩下的袜子(左右不同颜色也不同)改变颜色和左右。对比此时是左袜子剩的多还是右袜子剩的多,如果左袜子剩的多就看左边的颜色数组计算,最后ans+(l-r)/2表示将多出的左袜子转换为右袜子,ans+(l+r)/2表示将部分袜子换颜色。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,l,r,nl,nr,ans;
int cl[200010],cr[200010],a[200010],b[200010];
void solve()
{
	ans=0;
	cin>>n>>nl>>nr;l=nl,r=nr;
	memset(cl,0,sizeof cl);
	memset(cr,0,sizeof cr);
	memset(a,0,sizeof a);
	memset(b,0,sizeof b);
	for(int i=0;i<nl;i++)
	{
		cin>>a[i];
		cl[a[i]]++;
		//l--;
	}
	for(int i=0;i<nr;i++)
	{
		cin>>b[i];
		if(cl[b[i]])
		{
			cl[b[i]]--;
			l--;
			r--;
		}
		else cr[b[i]]++;
	}
//	cout<<l<<' '<<r<<' '<<endl;
	if(l>=r)
	{
		for(int i=0;i<nl;i++)
		{
			if(cl[a[i]]>=2&&l>r)
			{
				ans++;
				cl[a[i]]-=2;
				l-=2;
			}
		}
	//	cout<<l<<' '<<r<<endl;
		ans+=(l-r)/2+(r+l)/2;
	}
	else
	{
		for(int i=0;i<nr;i++)
		{
			if(cr[b[i]]>=2&&r>l)
			{
				ans++;
				cr[b[i]]-=2;
				r-=2;
			}
		}
		ans+=(r-l)/2+(r+l)/2;
	}
	cout<<ans<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	solve();
}

PS:在这个位置

if(l>=r)
	{
		for(int i=0;i<nl;i++)
		{
			if(cl[a[i]]>=2&&l>r)
			{
				ans++;
				cl[a[i]]-=2;
				l-=2;
			}
		}

之前依次遍历颜色过不去,现在还没有找出原因QAQ,大神们看出来的话请说一下(递话筒)
D. Berland Regional
题意:输入n,之后输入n个ui表示学校,n个si表示学生的学习能力,找出k分别取1-n时各学校派出的学生的总编程能力的最值。
思路:首先按照学校不同将学生放入对应map中,对学生的编程能力从大到小排序,算出对应前缀和,ans加一下各学院的就可以了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n;
bool cmp(int a,int b)
{
	return a>b;
}
void solve()
{
	cin>>n;
	map<int,vector<int>> mp;
	vector<int> un(n+1),ans(n+1);
	for(int i=1;i<=n;i++)cin>>un[i];
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		mp[un[i]].push_back(x);
	}
	for(auto [u,x]:mp)
	{
		sort(x.begin(),x.end(),cmp);
		int len=x.size();
		vector<int> p(len+1);
		for(int i=1;i<=len;i++)p[i]=p[i-1]+x[i-1];
		for(int i=1;i<=len;i++)ans[i]=ans[i]+p[len-len%i];
	}
	for(int i=1;i<=n;i++)cout<<ans[i]<<' ';
	cout<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	solve();
}

哈哈又学到一个

for(auto [u,x]:mp)//遍历map

E. Restoring the Permutation
题意:给出数组q,qi=max(p1,p2,…,pi).求p数组的最小字典序和最大字典序
思路:最开始想着通过遍历求出对应的数值,T在了第三了,最后通过set求出。
求最小字典序时,若数字第一次出现就输出该数字,否则输出比该数字小的且未输出过的最小的数字。
求最大字典序是,若数字第一次出现就输出该数字,否则输出比该数字小的且未输出过的最大的数字。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n;
int a[200010];
void solve()
{
	cin>>n;
	set<int> s;
	for(int i=1;i<=n;i++)
	{
		s.insert(i);
	}
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)
	if(a[i]!=a[i-1])
	{
		cout<<a[i]<<' ';s.erase(a[i]);
	}
	else cout<<*s.begin()<<' ',s.erase(*s.begin());
	for(int i=1;i<=n;i++)s.insert(i);cout<<endl;
	for(int i=1;i<=n;i++)
	{
		if(a[i]==a[i-1])
		{
			cout<<*prev(s.lower_bound(a[i]))<<' ';
			s.erase(*prev(s.lower_bound(a[i])));
		}
		else cout<<a[i]<<' ';s.erase(a[i]);
	}
cout<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	solve();
}

F. Planar Reflections
题意:有n个平面和D(k)光束,每次穿过一个平面会反射出一个反方向的D(k-1),k=1时不再反射,问最后有多少个不同的光线
例如当n=2,k=3时
在这里插入图片描述
此时有不同的光线 {D(3),D(2),D(2),D(1)},答案为4;
思路:动态规划(没想到QAQ)dp[j][i]表示穿过j个平面此时k为i的不同光线数。转移方程为 d p [ j ] [ i ] = ( d p [ n − j ] [ i − 1 ] + d p [ j − 1 ] [ i ] ) dp[j][i]=(dp[n-j][i-1]+dp[j-1][i])%mod; dp[j][i]=(dp[nj][i1]+dp[j1][i])
此状态由穿过j-1个平面,k为i和穿过n-j个平面,k=i-1共同组成。循环顺序为先循环光束,再循环平面。首先讨论光束的分裂次序。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,ans;
int mod=1e9+7;
int dp[1010][1010];
void solve()
{
	memset(dp,0,sizeof dp);
	cin>>n>>k;
	for(int i=1;i<=k;i++)dp[0][i]=1;
	for(int i=1;i<=n;i++)dp[i][1]=1;
	for(int i=1;i<=k;i++)
	for(int j=1;j<=n;j++)
	dp[j][i]=(dp[n-j][i-1]+dp[j-1][i])%mod;
	cout<<dp[n][k]<<endl;
}
 signed main()
 {
 	cin>>T;
 	while(T--)
 	solve();
 }

G. Building a Fence
题意:给出各位置路面高度,两个栅栏需要互相连通,每个栅栏距离地面不应超过k-1,问所给样例是否满足条件
思路:每次计算出下一个栅栏的范围,判断是否符合范围即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,h[200010];
void solve()
{
	cin>>n>>k;
	for(int i=0;i<n;i++)cin>>h[i];
	int l=h[0],r=h[0]+k;
	bool f=0;
	for(int i=1;i<n-1;i++)
	{
		if(l>=h[i]+k-1+k)
		{
			f=1;
			break;
		}
		if(r<=h[i])
		{
			f=1;
			break;
		}
		l=max(l-k+1,h[i]);
		r = min(r - 1, h[i] + k - 1) + k;//r-1由于最小要有1米连接
	}
	if(l>=h[n-1]+k)f=1;
	if(r<=h[n-1])f=1;
	if(f)cout<<"NO"<<endl;
	else cout<<"YES"<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	solve();
}

H. Ceil Divisions
题意:给一个数字n得数字a[i]=i,判断能否通过选择x,y;x!=y;使
a x = ⌈ a x / a y ⌉ ax=⌈ax/ay⌉ ax=ax/ay
最终使数组只有1个2,剩下的都是1、
思路:对于n找到y大于n/y上取整的数,将这些书都除以n。之后将n除以该数字两次,递归调用将参数改为该数字即可。

#include<bits/stdc++.h>
//#define int long long
using namespace std;
int T,n;
void w(int n,vector<pair<int,int>> &ans)
{
	if(n==2)return ;
	int y = max((int)1, (int)sqrt(n) - 1);
	while (y < (n + y - 1) / y)
		y++;
	for(int i=y+1;i<n;i++)
	ans.emplace_back(i,n);
	ans.emplace_back(n,y);
	ans.emplace_back(n,y);
	w(y,ans);
}
void solve()
{
	cin>>n;
	vector<pair<int,int>> ans;
	w(n,ans);
	cout<<ans.size()<<endl;
	for(auto x:ans)cout<<x.first<<' '<<x.second<<endl;
}
int main()
{
	cin>>T;
	while(T--)
	solve();
}

I. Pekora and Trampoline
题意:从任意一点i起跳,每次可到达i+a[i]的位置,此时a[i]–;减到1时就不再减小,问至少跳几次使所有的a[i]都变为1
思路:对于每个i而言,可对i+2至i+a[i]产生影响,将所有的影响相加,不够的次数加入ans即可,够的话b[i+1]+=(b[i]-a[i]+1);

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,a[200010],b[200010];
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],b[i]=0;
	for(int i=1;i<=n;i++)
	for(int j=i+2;j<=min(n,a[i]+i);j++)b[j]++;
	int ans=0;
	for(int i=1;i<=n;i++)
	if(a[i]>b[i])ans+=(a[i]-b[i]-1);
	else b[i+1]+=(b[i]-a[i]+1);
	cout<<ans<<endl;
}
signed main()
{
	cin>>T;
	while(T--)
	solve();
}

J. RPD and Rap Sheet (Easy Version)

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k;
void solve()
{
	cin>>n>>k;
	cout<<0<<endl;
	int ans=1;
	int t;cin>>t;
	while(t==0)
	{
		cout<<(ans^(ans-1))<<endl;
		cin>>t;
		ans++;
	}
 } 
 signed main()
 {  
    ios::sync_with_stdio(0);
    cin.tie(0);
 	cin>>T;
 	while(T--)
 	solve();
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值