"蔚来杯"2022牛客暑期多校训练营1

首先不得不说 题出的质量很高

Villages: Landlines

真的吐槽题目描述真的太冗长了 英文读起来很麻烦

其实就是让你把所有圆都连接起来 求空缺部分的长度

直接排个序然后线性扫一遍就好

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int n;
ll ans;
struct node{
	ll L,R;
}a[maxn];
bool cmp(node aa,node bb){
	if(aa.L!=bb.L)
	return aa.L<bb.L;
	return aa.R<bb.R;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		ll x,r;
		scanf("%lld%lld",&x,&r);
		a[i].L=x-r,a[i].R=x+r;
	}
	sort(a+1,a+1+n,cmp);
	ll nowL=a[1].L,nowR=a[1].R; 
	for(int i=2;i<=n;i++){
		if(a[i].L<=nowR)
			nowR=max(nowR,a[i].R);
		else {
				ans+=a[i].L-nowR;
				nowL=a[i].L,nowR=a[i].R;
			}
	}
	cout<<ans<<endl;
     return 0;
}

Grab the Seat!


这个题目两条直线相交很好想到 但是想到将相交的区域分为上下两部分更为关键 因为这样才能为后续线性扫一遍打基础

我们依次扫描1 2 3 三个点

因为 2 的斜率比 1 小 所以此时第二行的最优解任为斜率 1

扫描到 3 时 斜率更大 最优解为 3 的斜率 并且此时最优解斜率 3 是不会影响 1 和 2 的 最优解

所以只要从下到上 从上到下 分别线性扫一遍即可

最后注意因为本身那个点也不在选择范围 可能算出来是整数 所以代码里面分子减一

#include <cstdio>
#include <iostream>
using namespace std;

const int maxN = 2e5 + 7;

int n, m, k, q, x[maxN], y[maxN], minY[maxN], con[maxN][2];

int main()
{
    scanf("%d%d%d%d", &n, &m, &k, &q);
    for(int i = 1; i <= k; ++i) 
        scanf("%d%d", &x[i], &y[i]);
    while(q--) {
        int num; scanf("%d", &num);
        scanf("%d%d", &x[num], &y[num]);
        for(int i = 1; i <= m; ++i)
            minY[i] = n + 1;
        for(int i = 1; i <= k; ++i)
            minY[y[i]] = min(minY[y[i]], x[i]);
        int now = 1; con[1][0] = minY[1] - 1;
        for(int i = 2; i <= m; ++i) {
            if((long long) (now - 1) * minY[i] < (long long) (i - 1) * minY[now]) 
                now = i;
            con[i][0] =  ((long long) (i - 1) * minY[now] - 1) / (now - 1);
        }
        now = m; con[m][1] = minY[m] - 1;   
        for(int i = m - 1; i >= 1; --i) {
            if((long long) (m - now) * minY[i] < (long long) (m - i) * minY[now])
                now = i;
            con[i][1] = ((long long) (m - i) * minY[now] - 1) / (m - now);
        }
        long long ans = 0;
        for(int i = 1; i <= m; ++i)
            ans += min(con[i][0], con[i][1]);
        printf("%lld\n", ans);
    }
    return 0;
}

Mocha and Railgun

比赛的时候感觉就像在做高中的解析几何

有关圆问题的关键还是要连接圆心创造半径!!!!无一例外

求导还是很关键的一点!!! 但是其实猜结论的话也可以 很明显这个题一定是一个位置特殊的点

斜边大于直角边不难吧 你叫我初中来我肯定一下就能想到 但是现在想到还是很难

#include<bits/stdc++.h>
using namespace std;
const double PI=acos(-1.0);
int main()
{
    int tt;cin>>tt;
    while(tt--)
    {
        double r,x,y,d;cin>>r>>x>>y>>d;
        double l=sqrt(x*x+y*y);
        double a=acos((l-d)/r),b=acos((l+d)/r);
        double ans=r*(a-b);
        printf("%.8f\n",ans);
    }
    return 0;
}

Lexicographical Maximum

裸的签到题 没啥好说的

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
string s; 
int main(){
	cin>>s;
	int len=s.size();
			bool pd=1;
			for(int i=0;i<len-1;i++)
			if(s[i]!='9')pd=0;
			if(pd==1){
				cout<<s;
			}else 
			for(int i=1;i<len;i++)
			cout<<9;
     return 0;
}

Chiitoitsu

这个题目描述太恶心了

最后要注意 手里的单牌只能是 1 3 5 7 9 13

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll p = 1e9 + 7;
int t;
ll dp[20][200];

ll ksm(ll a,ll k)
{
    ll res = 1;
    while(k){
        if(k & 1) res = res * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return res;
}

int main()
{
    for(ll i = 1;i <= 13;i += 2){
        for(ll j = 3;j <= 123;j ++){
        	ll t=0;
			if(i-2>=0)t=dp[i-2][j-1]; 
            dp[i][j] = (1 + (((i * 3) * ksm(j,p - 2) % p) * t % p) + (((j - i * 3) * ksm(j,p - 2) % p) * dp[i][j - 1] % p)) % p;
		}
    }
    cin >> t;
    for(int Case = 1;Case <= t;Case ++){
        map<string,int> mp;
        string s;
        cin >> s;
        int n = 0;
        for(int i = 0;i < s.length();i += 2){
            string tmp = "";
            tmp += s[i];
            tmp += s[i + 1];
            mp[tmp] ++;
        }
        for(int i = 0;i < s.length();i += 2){
            string tmp = "";
            tmp += s[i];
            tmp += s[i + 1];
            if(mp[tmp] == 1) n ++;
        }
        cout << "Case #" << Case << ": " << dp[n][123] << '\n';
    }
    return 0;
}

Serval and Essay

能看出是启发式合并 但是还是很难

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
set<int> s[N],in[N];
int fa[N] ,sz[N];

int f(int x){
	return x==fa[x]?x:fa[x]=f(fa[x]);
}

void merge_(int x,int y){
	x=f(x),y=f(y);
	if(x==y)return;
	if(in[x].size()<in[y].size())swap(x,y);
	sz[x]+=sz[y];
	vector<pair<int,int> >v;
	for(auto t:in[y]){
		in[x].insert(t);
		s[t].erase(y);
		s[t].insert(x);
		if(s[t].size()==1)v.push_back({t,x});
	}
	fa[y]=x;
	for(auto t:v)merge_(t.first,t.second);
}

int main(){
	cin.tie(0);cout.tie(0);
	int t;
	cin>>t;
	for(int _=1;_<=t;_++){
		int n;cin>>n;
		for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1,s[i].clear(),in[i].clear();
		for(int i=1;i<=n;i++){
			int k;cin>>k;
			while(k--){
				int x;cin>>x;
				s[i].insert(x);
				in[x].insert(i);
			}
		}
		for(int i=1;i<=n;i++){
			if(s[i].size()==1)merge_(*s[i].begin(),i);
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			ans=max(ans,sz[i]);
		}
		printf("Case #%d: %d\n", _, ans);
	}
	return 0;
} 
posted @ 2022-07-22 10:41  wzx_believer  阅读(58)  评论(0编辑  收藏  举报