"蔚来杯"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;
}