A.Villages: Landlines
题意:题目给出若干个区间,求将各个区间全部相连的最短距离。
分析:先将有重叠部分的区间进行合并,将合并后的区间存在一个数组中,遍历一遍数组就可以了。
反思:①当时真的读题读到心态爆炸,读了两遍都不知道题目在说什么,最后大胆猜测了一下题意,交了一发过了。幸好当时没继续读第四遍....
②区间合并的板子是现拿现用的(我怎么什么都不会 呜呜呜)
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int n,x,r;
vector< pair<int,int> > itv; // interval
bool cmp (const pair<int,int>&a, const pair<int,int> &b) { return a.first < b.first; }
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x>>r;
itv.push_back( make_pair(x-r,x+r) );
}
sort(itv.begin(),itv.end(),cmp);
int len=itv.size();
bool flag=false;
vector< pair<int,int> > res;
for (int i = 1; i < len; i++)
{
int st = itv[i - 1].first;
int ed = itv[i - 1].second;
while (i < len && itv[i].first <= ed)
{
ed = max(ed, itv[i].second);
if (i == len - 1) flag = true;
i++;
}
res.push_back({st, ed});
}
if (!flag)
{
res.push_back({ itv[len-1].first, itv[len-1].second});
}
sort(res.begin(),res.end(),cmp);
int ans=0;
if(res.size()==1) cout<<"0"<<'\n';
else
{
int rt=res[0].second;
for(int i=1;i<res.size();i++)
{
ans+=res[i].first-rt;
rt=res[i].second;
}
cout<<ans<<'\n';
}
return 0;
}
合并区间的板子:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int n,l,r;
vector< pair<int,int> > itv; // interval
//用pair来存区间,两个元素分别代表区间的起点、终点
bool cmp (const pair<int,int>&a, const pair<int,int> &b)
{ return a.first < b.first; } //按照起点大小排序
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>l>>r;
itv.push_back( {l,r} );
}
sort(itv.begin(),itv.end(),cmp);
int len=itv.size(); //区间总数
bool flag=false;
vector< pair<int,int> > res; //用来存合并之后的区间
for (int i = 1; i<len; i++)
{
int st = itv[i - 1].first;
int ed = itv[i - 1].second;
while (i < len && itv[i].first <= ed)
{
ed = max(ed, itv[i].second); //右边界逐渐向外延伸
if (i == len - 1) flag = true;//标记最后一个区间的合并情况
i++;
}//循环的目的是顺着一直合并
res.push_back({st, ed}); //记录合并起来的大区间
}
if (!flag)
{
res.push_back({ itv[len-1].first, itv[len-1].second});
}//处理特殊的尾元素
sort(res.begin(),res.end(),cmp);
return 0;
}
D. Mocha and Railgun
题意:有一个圆心在原点,半径为1的大圆,有一个小圆位于大圆内,给出小圆的圆心和半径,求小圆投影到大圆上的弧长最长为多少。
分析:大胆推测一波,平时或者垂直时取到最值。用画图软件简单画出了几种情况,发现是红线情况下弧长最长。
去掉无用的情况,简化图形如下所示:
下图推导求解过程:
易得∠MON
代码如下:
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
const int N=2e5+5;
int main()
{
int T; cin>>T;
while( T-- )
{
int r,x,y,d;
cin>>r>>x>>y>>d;
double OQ = sqrt((LL)x * x + (LL)y * y);
printf("%.12lf\n", (acos((OQ - d) / r) - acos((OQ + d) / r)) * r);
}
return 0;
}
G. Lexicographical Maximum
题意:给出一个数n,输出比n小的数中字典序最大的。
分析:要字典序最大,我们要在前面尽可能多地输出9。由于要比n小,我们少输出一位即可。如果整个字符串除了最后一位均为9,我们直接输出原串就行。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
string s;
int len;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>s;
ll len=s.size();
bool flag=true;
for(int i=0;i<len-1;i++)
{
if(s[i]!='9')
{
flag=false;
break;
}
}
if(!flag) for(int i=1;i<=len-1;i++) cout<<"9";
else cout<<s;
cout<<'\n';
return 0;
}
I. Chiitoitsu
先放代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int mod=1000000007;
inline ll qpow(ll a,ll b,ll c){ll res=1%c;a%=c;while(b>0){if(b&1)res=res*a%c;a=a*a%c;b>>=1;}return res;}
int t,T;
vector<vector<ll>> f(30,vector<ll>(150,0));
void getdp()
{
for(int r=1;r<=125;r++)
{
ll inv=qpow(r,mod-2,mod);
for(int s=1;s<=13;s++)
{
if(r<s*3) continue;
if(s==1) f[s][r] = ( 1 + (r-3)*inv%mod*f[s][r-1] )%mod;
else f[s][r] = ( 1 + 3*s*inv%mod*f[s-2][r-1]%mod + (r-3*s)*inv%mod*f[s][r-1]%mod )%mod;
}
}
}
void solve()
{
string s;
cin>>s;
map<int,int> Manzu,Pinzu,Souzu,Jihai;
for(int i=0;i<s.size();i+=2)
{
if(s[i+1]=='m') Manzu[s[i]-'0']++;
if(s[i+1]=='p') Pinzu[s[i]-'0']++;
if(s[i+1]=='s') Souzu[s[i]-'0']++;
if(s[i+1]=='z') Jihai[s[i]-'0']++;
}
int sgl=0; //single 统计单牌的数量
for(int i=1;i<=9;i++)
{
if(Manzu[i]%2) sgl++;
if(Pinzu[i]%2) sgl++;
if(Souzu[i]%2) sgl++;
if(Jihai[i]%2) sgl++;
}
cout<<"Case #"<<T<<": "<<f[sgl][123]<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>t;
getdp();
for(T=1;T<=t;T++)
{
solve();
}
return 0;
}
一些需要好好理解的地方:
①逆元的处理
②概率与期望(特别是dp时的方程转移)
③什么样的策略是最优的? 如果摸到的牌刚好能与手上的单牌配对,则留下此牌,另外打出一张单牌。如果摸到的牌不能与手上的单牌配对,则立刻打出摸到的牌。