2023年天梯赛选拔-部落划分

Posted xjwrr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2023年天梯赛选拔-部落划分相关的知识,希望对你有一定的参考价值。

题目链接:https://www.luogu.com.cn/problem/P4047

感受:比赛时秒认为是二分,但二分的细节很多且不好处理,但我就是要二分。

主要死在对并查集还不够熟悉,本题二分判断有几个部落只能通过并查集来实现,普通的模拟无法实现。

思路:对答案进行二分,当算出来的联通的数目大于题目给定的,说明二分的答案偏小。反之答案偏大。

这里说一下当两点间的距离与二分的答案相等的情况,如本题样例,当二分答案为0.9999时,联通块数目是4,当二分答案为1时,连通块数目是1,并没有二分到k,我们只需要去掉二分答案为1时的边的长度为1的边,这样联通块的数目就与题目给定的相等了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
typedef pair<int,int>P;
int p[N];
P edge[N];
int n,k;
int find(int x)
    if (x!=p[x]) p[x] = find(p[x]);
    return p[x];

double get(int x1,int y1,int x2,int y2)
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

bool check(double mid)
	int cnt = 0;
	for (int i=1;i<=n;i++) p[i] = i;
	for (int i=1;i<=n;i++)
	    for (int j=i+1;j<=n;j++)
	        double d = get(edge[i].first,edge[i].second,edge[j].first,edge[j].second);
	        if (d<=mid)
	            int X = find(i),Y = find(j);
	            p[X] = Y;
	        
	    
	
	for (int i=1;i<=n;i++)
	    if (p[i]==i) cnt++;
	
	if (cnt>=k)  return 1;
	return 0;

int main()
	cin>>n>>k;
	for (int i=1;i<=n;i++) cin>>edge[i].first>>edge[i].second;
	double l = 0,r = 20000;
	while(r-l>1e-9)
		double mid = (l+r)/2;
		if (check(mid)) l = mid;
		else r = mid;
	
	printf("%.2f",l);
	return 0;

2022年天梯赛上海理工大学校内选拔赛部分题 题解

题目地址:https://ac.nowcoder.com/acm/contest/30532
题目难度偏简单,做出了7道快8道,认真做可能估计8-9道左右。

目录

A+B Problem【签到】

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N],n;
int main(void) 

    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i],b[i]=a[i];
    sort(a,a+n);
    for(int i=0;i<n;i++) 
    
        if(b[i]==a[n-1]) cout<<b[i]+a[n-2]<<" "; //是最大值,则加倒数第二数
        else cout<<b[i]+a[n-1]<<" ";
    
	return 0;

Komorebi的数学课【快速幂板子】

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
LL n;
LL quick(LL a,LL b,LL p)

    LL sum=1;
    while(b)
    
        if(b&1) sum=sum*a%p;
        b>>=1;
        a=a*a%p;
    
    return sum%p;

int main(void) 

    cin>>n;
    cout<<quick(n,n,n+2)<<endl;
	return 0;

次佛锅【哈希表 字符串处理】


关键点在于处理,第一行的数据。

#include<bits/stdc++.h>
using namespace std;
string a,b;
map<string,int>mp;
vector<string>ve;
int main(void) 

    getline(cin,a);
    stringstream l(a);
    int cnt=0;
    while(l>>b)
    
        cnt++;
        ve.push_back(b);
        if(cnt==2)//说明一个名字  一个数字了
        
            mp[ve[0]]+=stoi(ve[1]);
            ve.clear();
            cnt=0;
        
    
    int n; cin>>n;
    while(n--)
    
        cin>>a;
        cout<<mp[a]<<endl;
    
	return 0;

Setsuna的K数列【k进制 思维】


就是k进制,之前见过类似的题目。关键在于读懂题。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int mod=1e9+7;
LL n,f[100],k;
vector<LL>ve;
int main(void) 
   
    cin>>n>>k;
    for(LL i=0,j=1;i<=31;i++,j=j*k%mod) f[i]=j%mod;
    LL sum=0;
    for(int i=31;i>=0;i--)
        if(n>>i&1) sum=(sum+f[i])%mod;
    cout<<sum;
	return 0;

Wiki下象棋【BFS】

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long int LL;
const int N=510;
int t,n,m,k,a,b,c,d;
int s[N][N],st[N][N],dist[N][N];
int bfs(int x,int y,int w)

    memset(st,0,sizeof st);
    memset(dist,0x3f,sizeof dist);
    queue<PII>q; q.push(a,b); st[a][b]=1; dist[a][b]=0;
    int dx[8]=;
    while(q.size())
    
        auto temp=q.front(); q.pop();
        int x=temp.first,y=temp.second;
        if(x==c&&y==d) return dist[x][y];
        if(w==1)
        
            int dx[8]=-2,-2,1,1,-1,-1,2,2;
            int dy[8]=-1,1,-2,2,-2,2,-1,1;
            for(int i=0;i<8;i++)
            
                int tempx=x+dx[i],tempy=y+dy[i];
                if(tempx<1||tempx>n||tempy<1||tempy>m) continue;
                if(st[tempx][tempy]) continue;
                if(s[tempx][tempy]) continue;
                st[tempx][tempy]=1;
                dist[tempx][tempy]=dist[x][y]+1;
                q.push(tempx,tempy);
            
        else
        
            int dx[8]=-2,-2,1,1,-1,-1,2,2;
            int dy[8]=-1,1,-2,2,-2,2,-1,1;
            int dx1[8]=-1,-1,0,0,0,0,1,1;//马脚
            int dy1[8]=0,0,-1,1,-1,1,0,0;//马脚
            for(int i=0;i<8;i++)
            
                int tempx=x+dx[i],tempy=y+dy[i];
                if(tempx<1||tempx>n||tempy<1||tempy>m) continue;
                if(st[tempx][tempy]) continue;
                if(s[tempx][tempy]) continue;
                if(s[x+dx1[i]][y+dy1[i]]) continue;//憋马脚了
                st[tempx][tempy]=1;
                dist[tempx][tempy]=dist[x][y]+1;
                q.push(tempx,tempy);
            
        
    
    return -1;

int main(void) 

    cin>>t;
    while(t--)
    
        scanf("%d%d%d%d%d%d%d",&n,&m,&k,&a,&b,&c,&d);
        memset(s,0,sizeof s);
        while(k--)
        
            int x,y; scanf("%d%d",&x,&y);
            s[x][y]++;
        
        int ans1=bfs(a,b,1);
        int ans2=bfs(a,b,2);
        printf("%d %d\\n",ans1,ans2);
    
	return 0;

黄金律法【贪心】

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e6+10;
int t,n,a[N],b[N];
bool cmp(int a,int b)return a>b;
int main(void) 

    cin>>t;
    while(t--)
    
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) scanf("%d",&b[i]);
        LL sum=0;
        sort(a+1,a+n+1);
        sort(b+1,b+n+1,cmp);
        for(int i=1;i<=n;i++) sum+=1ll*a[i]*b[i];
        cout<<sum<<endl;
    
	return 0;

天气预报【双指针】


很容易的分析出,它是有单调性的。即当右边界满足的时候,后面的也一定满足。
故可以双指针来维护,需要注意的是 a==0 b==0 这种情况,还需额外加1。因为题目说了可以啥都不选。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef unsigned long long int LL;
LL n,a,b,s[N];
string c;
bool check(int i,int j)

    int l=s[j]-s[i-1];
    int r=(j-i+1)-l;
    if(l>=b&&r>=a) return true;
    return false;

int main(void)

	cin>>n>>a>>b>>c;
	c="*"+c;
	for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i]-'0';
	long long int ans=0;
	for(int i=1,j=1;i<=n;i++)
	
	    while(j<=n&&!check(i,j)) j++;
	    while(j<=n&&j<i) j++;
	    if(j<=n&&check(i,j)) ans+=(n-j+1);
	
	if(!a&&!b) ans++;
	cout<<ans;
	return 0;

叠硬币【DP】



这道还是挺有意思的,难度就在于输出,以及字典序最小输出。
我们可以从大到小排序。这样的话它会一直的覆盖,此时最后的就是做小的字典序。
存前驱结点可以用一个数组来存。

#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int f[N],a[N],pre[N],n,m; //pre[i] 表示放到i高时的 最后一个硬币的高度
bool cmp(int a,int b)return a>b;
int main(void)

    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1,cmp);
    for(int i=0;i<N;i++) f[i]=1e9;
    f[0]=0,pre[0]=0;
    for(int i=1;i<=n;i++)
    
        for(int j=m;j>=a[i];j--)
        
            if(f[j]>f[j-a[i]]+1 || (f[j] == f[j-a[i]]+1 && pre[j] > a[i]))
                f[j] =以上是关于2023年天梯赛选拔-部落划分的主要内容,如果未能解决你的问题,请参考以下文章

2023年团体程序设计天梯赛 题解

牛客 2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛 签到题13题

牛客 2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛 签到题13题

天梯赛选拔2020.3.3

天梯赛 L2-024. 部落

pta天梯赛含金量