战绩and总结
又被兴哥吊锤了,打了一个多小时锤皮球了被暴两题555
A - Yet Another Dividing into Teams
题意:
有一个长度为n的序列a1,a2…an,将他们分为若干组,使得每一组没有两个数的差为1,使分的组数尽可能少。
思路:
排序之后判断最大的和最小的两个的和与三个的和看看能否相等即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
flag:while(t--) //t
{
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++) cin>>a[i]; //n
sort(a,a+n); //nlog(n)
for(int i=0;i<n-1;i++) //n
{
if(a[i+1]-a[i]==1)
{
cout<<2<<endl;
goto flag;
}
}
cout<<1<<endl;
}
}
B1 - Books Exchange (easy version)
题意:
有n个孩子,每个孩子都在读一本独特的书。在任何一天结束时,第i个孩子将把他的书交给第pi个孩子(如果i = pi,则该孩子将把他的书交给他自己)。保证pi的所有值都是从1到n的不同整数(即p是一个排列)。序列p每天都不变化,它是固定的。
例如,如果n = 6且p = [4,6,1,3,5,2],则在第一天结束时,第一个孩子的书将属于第四个孩子,第二个孩子-第二个孩子将属于第六个孩子,依此类推。在第二天结束时,第一个孩子的书将属于第三个孩子,第二个孩子将属于第二个孩子,依此类推。
您的任务是确定从1到n的每个i,第i个孩子的书第一次返还给他的天数。
考虑以下示例:p = [5,1,2,4,3]。第一个孩子的书将传递给以下孩子:
第一天之后,它将属于第五个孩子, 第2天之后,它将属于第3个孩子, 第三天之后,它将属于第二个孩子, 在第4天之后,它将属于第一个孩子。 因此,第四天之后,第一个孩子的书将归还其所有者。第四天的书将在整整一天后第一次归还给他。
您必须回答q个独立查询。
思路:easy version嘛,暴力搞搞即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
int a[maxn];
int main()
{
int n,i,j,t;
cin>>t;
while(t--)
{
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
for(i=1;i<=n;i++)
{
int d1=a[i],cnt=0;
while(1)
{
cnt++;
if(d1==i)
{
cout<<cnt<<" ";
break;
}
else
{
d1=a[d1];
}
}
}
cn;
}
return 0;
}
B2. Books Exchange (hard version)
题意:唯一不同的地方是数据范围很大
思路:
做法①:并查集:(偷的)
我们使用并查集维护每个点到对应根的距离以及最小环的大小。类似地,此题也可以使用并查集解决。维护距离操作完全相同,维护环时开一个ansans数组记录每个点所在环的大小,每次findfind时更新距离,合并时更新换的大小即可。
这里还有一点小问题,对于每个环中不在最后一条边上的点(即不是“封口”的点),更新ansans数组时,这些点并不会被更新到。所以我们在输出时,将ans[i]ans[i]改为ans[find(i)]ans[find(i)]即可。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ff first
#define ss second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int INF=2147483647;
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 f[200086],n,q,ans[200086],d[200086];
int find(int x)
{
if(x!=f[x])
{
int last=f[x];
f[x]=find(f[x]);
d[x]+=d[last];
}
return f[x];
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)f[fx]=fy,d[x]=d[y]+1;
else
{
ans[x]=min(ans[x],d[x]+d[y]+1);
ans[y]=min(ans[x],d[x]+d[y]+1);
}
}
int main()
{
q=read();
while(q--)
{
memset(f,0,sizeof(f));
memset(ans,0x7f,sizeof(ans));
memset(d,0,sizeof(d));
n=read();
rep(i,1,n)f[i]=i;
rep(i,1,n)
{
int p=read();
merge(i,p);
}
rep(i,1,n)printf("%d ",ans[find(i)]);
printf("\n");
}
return 0;
}
做法②:dfs
#include <bits/stdc++.h>
const int maxn = 2e5+50;
using namespace std;
typedef long long ll;
int a[maxn], mark[maxn];
void dfs(int x){ //记忆化搜索
if(mark[a[x]]) //当前如果被遍历过搜到过那么返回
return;
else{
mark[a[x]] = mark[x] + 1;//否则更新距离并且搜下一个点
dfs(a[x]);
}
mark[x] = mark[a[x]];//在搜完之后再把值赋回来
}
int main()
{
int q, n;
scanf("%d", &q);
while(q--){
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
mark[i] = 0;
}
for(int i=1; i<=n; i++){
if(mark[i] == 0){
mark[i] = 1;
dfs(i);
}
printf("%d ", mark[i]);
}
printf("\n");
}
return 0;
}
C1 - Good Numbers (easy version)
题意:
思路:easy version 可以有很多做法,暴力最简单啦,不过我没想明白,我是暴力然后预处理一下答案,直接搜
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int cnt;
int ans[maxn];
bool vis[10];
void dfs(int step,int sum)
{
for(int i=step;i<=9;i++)
{
if(vis[i]==0)
{
sum+=pow(3,i);
vis[i]=1;
dfs(step+1,sum);
sum-=pow(3,i);
vis[i]=0;
}
}
ans[cnt++]=sum;
return ;
}
int main()
{
int n,i,j,t;
dfs(0,0);
sort(ans,ans+cnt);
int d1=unique(ans,ans+cnt)-ans;
cin>>t;
while(t--)
{
cin>>n;
for(i=1;i<d1;i++)
{
if(ans[i]>=n)
{
cout<<ans[i]<<endl;
break;
}
}
}
return 0;
}