A:Villages: Landlines
题意:(题目写的花里胡哨的)
n
n
n个区间
[
x
i
−
r
i
,
x
i
+
r
i
]
[x_i-r_i,x_i+r_i]
[xi−ri,xi+ri],两个区间连通当且仅当他们有交集。现可以添加任意区间,使得所有区间连通,求添加区间长度和的最小值。
(
n
≤
2
∗
1
e
5
)
(n \leq 2*1e5)
(n≤2∗1e5)
题解: 将
n
n
n个区间按
x
i
−
r
i
x_i-r_i
xi−ri排序,扫一遍则可得到未被覆盖的区间的长度。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200100;
struct node{
ll x,r;
}h[N];
int n;
ll ans;
bool cmp(node a,node b){return a.x-a.r < b.x-b.r;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&h[i].x,&h[i].r);
sort(h+1,h+n+1,cmp);
ll r=h[1].x+h[1].r;
for(int i=2;i<=n;i++){
if(r<h[i].x-h[i].r) ans+=h[i].x-h[i].r-r;
r=max(r,h[i].x+h[i].r);
}
printf("%lld",ans);
return 0;
}
D:Mocha and Railgun
题意: 给定一个圆心在
(
0
,
0
)
(0,0)
(0,0)半径为R的圆,一点
P
P
P在绝对圆内,以
P
P
P为中点朝任意方向发射一段长为
2
∗
d
2*d
2∗d的线段,求该线段在
x
x
x轴上投影对应弧长的长度(保证线段在圆内)。
题解: 因为圆的对称性,线段方向任意相当于
P
P
P在一个小圆上转,线段方向始终是平行于
x
x
x轴的。经过理性证明 (瞎猜) ,得到当
P
P
P在
x
x
x轴上时,弧长最大。利用反三角函数算出弧长对应圆心角,进而得到弧长。
#include<bits/stdc++.h>
using namespace std;
int T;
double R,x,y,d,r,ans;
int main()
{
scanf("%d",&T);
while(T--){
scanf("%lf%lf%lf%lf",&R,&x,&y,&d);
r=sqrt(x*x+y*y);
double A1=acos((r-d)/R);
double A2=acos((r+d)/R);
ans=abs(A1-A2)*R;
printf("%.8lf\n",ans);
}
}
G:Lexicographical Maximum
题意: 给定数字
n
n
n,输出
1
∼
n
1\sim n
1∼n中字典序最大的数字。
(
1
(1
(1
≤
\leq
≤
n
n
n
≤
\leq
≤
1
0
1000000
10^{1000000}
101000000
)
)
)
题解: 最大值只可能是n或
9
∗
(
l
e
n
−
1
)
9*(len-1)
9∗(len−1),取较大值即可。
#include<bits/stdc++.h>
using namespace std;
string s,ans;
int n;
int main()
{
cin>>s;
for(int i=1;i<s.size();i++) ans+="9";
ans=max(ans,s);
cout<<ans<<endl;
}
I.Chiitoitsu
题意: 初始手牌有
13
13
13张麻将牌,相同牌至多出现
2
2
2张,每轮可以从牌堆摸牌,若达成七对子则自摸胡牌,若不然则选择手牌中某张牌并丢弃之,给定初始手牌,求最优策略下达成七对子的期望轮数。多组数据,数据组数不超过
1
0
5
10^5
105组
题解: 最优策略为:若摸到的牌能和手牌凑成对子,则丢弃一张单牌;否则丢弃摸到的牌。考虑
d
p
dp
dp期望:设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示当前手牌中有
i
i
i张单牌且牌堆中剩余
j
j
j张牌时达成七对子的期望轮数,则
f
[
i
]
[
j
]
=
{
1
+
j
−
3
j
∗
f
[
i
]
[
j
−
1
]
+
3
j
∗
f
[
0
]
[
j
−
1
]
,
i
=
1
1
+
j
−
3
∗
i
j
∗
f
[
i
]
[
j
−
1
]
+
3
∗
i
j
∗
f
[
i
−
2
]
[
j
−
1
]
,
i
≠
1
f[i][j]= \left\{ \begin{array}{rl} 1+\frac{j-3}{j}*f[i][j-1]+\frac{3}{j}*f[0][j-1] & \text{, } i=1\\ 1+\frac{j-3*i}{j}*f[i][j-1]+\frac{3*i}{j}*f[i-2][j-1] & \text{, } i \neq 1 \end{array} \right.
f[i][j]={1+jj−3∗f[i][j−1]+j3∗f[0][j−1]1+jj−3∗i∗f[i][j−1]+j3∗i∗f[i−2][j−1], i=1, i=1
注意该转移方程与具体初始输入无关,所以需要先预处理出来,否则会
T
T
T。
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int T,cnt,f[25][250],vis[555];
char s[111];
int quick(int x,int p)
{
int as=1;
while(p){
if(p&1) as=1ll*as*x%mod;
x=1ll*x*x%mod;
p>>=1;
}
return as;
}
int main()
{
for(int i=1;i<=13;i++){
for(int j=1;j<=136-13;j++){
if(i==1) f[i][j]=(1ll*f[i][j-1]*(j-3)%mod*quick(j,mod-2)%mod+3ll*f[0][j-1]%mod*quick(j,mod-2)%mod+1ll)%mod;
else f[i][j]=(1ll*f[i][j-1]*(j-3*i)%mod*quick(j,mod-2)%mod+3ll*f[i-2][j-1]*i%mod*quick(j,mod-2)%mod+1ll)%mod;
}
}
scanf("%d",&T);
for(int t=1;t<=T;t++){
memset(vis,0,sizeof(vis));
scanf("%s",s+1);
int len=strlen(s+1);
cnt=0;
for(int i=1;i<=len;i+=2){
vis[(s[i]-'0')*26+s[i+1]-'a']++;
}
for(int i=1;i<=len;i+=2){
if(vis[(s[i]-'0')*26+s[i+1]-'a']<2) cnt++;
}
printf("Case #%d: %d\n",t,f[cnt][136-13]);
}
return 0;
}