前言
下了场雪,差点没给学校埋了,教学楼时不时停个电、断个网的。
这些我都能忍,为啥还能有只把灯的电给停了的呢?差点就以为是自己给机房灯干坏了。
这让我想到了之前宿舍楼的光缆被挖掘机挖断的事情,给大家伙逗乐了属实是。
1004 - Wave(枚举/动态规划)
比赛链接:https://acm.dingbacode.com/submit.php?pid=6570
题目大意
如果一个序列 a a a满足条件:
- 序列 a a a中处于奇数位置的数字全都是 x x x;
- 序列 b b b中处于偶数位置的数字全都是 y y y;
- x ≠ y x≠y x=y;
那么我们称序列 a a a是一个波动序列。
现在给出一个长度为n的序列s,序列s中所有的元素都小于c。
请求出序列a中最长的波动子序列的长度。
思路
由于
c
c
c最大才是
100
100
100,所以我们可以直接用枚举解决。
用
v
e
c
t
o
r
vector
vector存储每个数字出现的位置,然后枚举奇数位与偶数位会是哪两个数字。
但如果
c
c
c的范围加大,博主建议用动态规划做,会省下不少时间。
但博主是个dp的fw,所以大家可以看一下https://blog.csdn.net/dabaitutunaitang/article/details/121238923对于B题的讲解,讲解的还是十分到位的。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int a[maxn];
int main()
{
int n,c;
while(cin>>n>>c)
{
vector<int> arr[105];
int ans=-1;
for(int i=1; i<=n; i++)
{
cin>>a[i];
arr[a[i]].push_back(i);
}
for(int i=1; i<=100; i++)
{
if(arr[i].size()==0)
continue;
int len1=arr[i].size();
for(int j=1; j<=100; j++)
{
if(arr[j].size()==0||i==j)
continue;
int len2=arr[j].size();
int l1=0,l2=0;
int lastpos=0;
int cnt=0;
while(true)
{
while(l1<len1&&arr[i][l1]<lastpos)
l1++;
if(l1==len1) break;
lastpos=arr[i][l1];
cnt++;
while(l2<len2&&arr[j][l2]<lastpos)
l2++;
if(l2==len2) break;
lastpos=arr[j][l2];
cnt++;
}
ans=max(ans,cnt);
}
}
cout<<ans<<endl;
}
}
1006 - String(思维)
比赛链接:https://acm.dingbacode.com/submit.php?pid=6572
题目大意
给出一个长度为n的字符串。
每次从字符串中随机取出一个字符,再放回去。
一共取4次,请问按照取字符的顺序组成的字符串有多少几率是"avin"呢?
请输出最简化分数形式。
若概率为0,则输出"0/1"。
思路
答案:
(
n
u
m
a
numa
numa:字符
a
a
a的个数,
n
u
m
v
numv
numv:字符
v
v
v的个数,
n
u
m
i
numi
numi:字符
i
i
i的个数,
n
u
m
n
numn
numn:字符
n
n
n的个数)
答案需要是最简分式,所以还需要求最大公约数。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e3+100;
ll a[maxn];
ll b[maxn];
int main()
{
int n;
while(cin>>n)
{
string ss;
map<char,int> mp;
cin>>ss;
for(int i=0;i<n;i++)
mp[ss[i]]++;
ll y=n*n*n*n;
ll x=mp['a']*mp['v']*mp['i']*mp['n'];
if(x==0) cout<<"0/1"<<endl;
else{
ll z=__gcd(x,y);
x/=z;
y/=z;
cout<<x<<"/"<<y<<endl;
}
}
}
1007 - Traffic(枚举)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6573
题目大意
Avin正在观察一个十字路口来往的车辆。
他发现有
n
n
n辆车是由东向西行驶,有
m
m
m辆车是由北向南行驶,每辆车都有自己到达十字路口的时间点。我们假设穿过十字路口不需要时间。
如果有一辆东→西方向的车在T时刻到达十字路口,还有一辆北→南方向的车也在T时刻到达十字路口,则两车可能发生碰撞,出现事故。
于是我们规定,所有北→南方向的车在到达十字路口时都需要等待
X
X
X个时刻才能继续行驶,以避免发生事故。
现在请你求出X的最小值是多少。
思路
由于题目中所有车到达的时刻ti
(所有的ai
与bi
统称为ti
)都在
1000
1000
1000以内,所以我直接枚举了
x
x
x的值,最多就是
1000
1000
1000而已。
每次只需要看北→南方向的车的到达时间加上 x x x之后是否还会出现在数组 a a a里即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int a[1050];
int b[1050];
int main()
{
int n,m;
while(cin>>n>>m){
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=m;i++)
cin>>b[i];
int x=0;
while(true){
int flag=1;
for(int i=1;i<=m;i++){
int pos=lower_bound(a+1,a+1+n,b[i]+x)-a;
if(a[pos]==b[i]+x){
flag=0;
break;
}
}
if(flag) break;
x++;
}
cout<<x<<endl;
}
}
1008 - Rng(规律+数论+逆元)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6574
题目大意
现在给出数字n。
Avin先在
[
1
,
n
]
[1,n]
[1,n]中随机挑出一个数字
r
r
r,再从
[
1
,
r
]
[1,r]
[1,r]中随机挑出一个数
l
l
l。这样Avin就获得了一个区间
[
l
,
r
]
[l,r]
[l,r]。
接下来Avin重复刚才的操作,又获得了一个区间
[
l
2
,
r
2
]
[l_2,r_2]
[l2,r2]。
问:两个区间相交的概率是多少?
假设这个值为
a
b
\frac{a}{b}
ba,请输出
a
b
\frac{a}{b}
ba%
(
1
e
9
+
7
)
(1e9+7)
(1e9+7)的值。
思路
首先是求出
a
b
\frac{a}{b}
ba的值。
我把
n
n
n为1,2,3,4,5
的情况自己模拟了一遍,发现是
(
n
+
1
)
(
2
∗
n
)
\frac{(n+1)}{(2*n)}
(2∗n)(n+1),尝试了一下就过了。
想看详细推导过程可以看这个https://blog.csdn.net/qq_42671946/article/details/96756347。
大佬nb,博主就是个靠运气过题的屑罢了。
剩下的就是求整体。
一开始没看出来
n
=
=
2
n==2
n==2的时候为啥是
750000006
750000006
750000006,自己求的明明是
3
4
\frac{3}{4}
43,怎么可能这么大。
后来想起了逆元,然后就明白了。
- 1 a \frac{1}{a} a1% m o d mod mod== a ( m o d − 2 ) a^{(mod-2)} a(mod−2),前提是 a a a与 m o d mod mod互质。
逆元证明详见https://blog.csdn.net/acdreamers/article/details/8220787。
我们又知道, 1 e 9 + 7 1e9+7 1e9+7是个质数,质数和任何数都互质,代码就出来了。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll quickpower(ll base,ll power)
{
ll result=1;
while(power){
if(power&1) result=(result*base)%mod;
power>>=1;
base=(base*base)%mod;
}
return result;
}
int main()
{
ll n;
while(cin>>n){
cout<<(n+1)*quickpower(n*2,mod-2)%mod<<endl;
}
}
1009 - Budget(思维)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6575
题目大意
给出 n n n个浮点数,每个浮点数都有 3 3 3个小数位。我们现在想要让所有的浮点数从 3 3 3位小数变为 2 2 2位小数( 1.001 → 1.00 1.001→1.00 1.001→1.00),这就要涉及到最后一位的取舍。
设最后一位小数为 x x x。
- 若 x < 5 x<5 x<5,则需要舍弃掉 x x x,付出 − 0.00 x -0.00x −0.00x的代价;
- 若 x > = 5 x>=5 x>=5,则需要进位,符出 0.00 ( 10 − x ) 0.00(10-x) 0.00(10−x)的代价;
请算出把 n n n个浮点数全部变成 2 2 2位小数所需要付出的代价总和。
思路
一开始用
d
o
u
b
l
e
double
double类型进行输入与处理,后来发现精度无法保证。
苦思一番之后想到可以用字符串存储,既解决了数据大小的问题,又方便我取最后一位数的值。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e3+100;
ll a[maxn];
ll b[maxn];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
double ans=0;
for(int i=0;i<n;i++)
{
char s[50];
scanf("%s",s);
int m=s[strlen(s)-1]-'0';
if(m>4)
ans+=10-m;
else
ans-=m;
}
printf("%.3f\n",ans/(1000*1.0));
}
}
1010 - Worker(思维+数学)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6576
题目大意
现在有
n
n
n个车间,
m
m
m个工人。
环境会影响工人的积极性,在第
i
i
i个车间工作的工人可以完成
a
i
a_i
ai个任务(是指一个人就能完成
a
i
a_i
ai个任务)。
现在请你求出一个分配工人的方案,使得每个车间最后完成的任务总数都是相同的。
每个工人只能且必须被分配到一个车间。
如果没有方案则输出"
N
O
NO
NO"。
思路
首先找特殊情况:
- 若
n==1
,此时我们直接让所有工人都去那一个车间即可; - 若
n>m
,这就无法保证每个车间至少要有一个工人的前提(为什么是前提自己想),输出NO
;
接下来讨论其他情况。
首先我们假设最后所有车间完成的任务数为ans
,那么ans
就应该是
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an的一个公倍数。
那么我们就可以先求出
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an的最小公倍数min_ans
,用min_ans
除ai
就可以得到每个车间最少需要的人数bi
,紧接着求出最少的总工人数sum
。此时如果m是sum的倍数,那说明我们只需要再给每个车间分配
(
m
s
u
m
−
1
)
∗
b
i
(\frac{m}{sum}-1)*bi
(summ−1)∗bi个人即可;否则就无法分配。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e3+100;
ll a[maxn];
ll b[maxn];
ll gcd(ll x,ll y){
return y==0?x:gcd(y,x%y);
}
int main()
{
ll n,m;
while(cin>>n>>m)
{
for(int i=1; i<=n; i++)
cin>>a[i];
if(n==1)
cout<<"Yes"<<endl<<m<<endl;
else if(n>m)
cout<<"No"<<endl;
else
{
ll ans=a[1];
for(int i=2;i<=n;i++){
ll x=__gcd(ans,a[i]);
ans=ans*a[i]/x;
}
ll sum=0;
for(int i=1; i<=n; i++)
{
b[i]=ans/a[i];
sum+=b[i];
}
if(m%sum==0)
{
ll k=m/sum;
cout<<"Yes"<<endl;
for(int i=1; i<=n; i++)
{
if(i!=1)
cout<<" ";
cout<<b[i]*k;
}
cout<<endl;
}
else
cout<<"No"<<endl;
}
}
}
1011 - Class(水题+初中数学)
比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6577
题目大意
已知:
a
+
b
=
x
,
a
−
b
=
y
a+b=x,a-b=y
a+b=x,a−b=y。
问给出
x
、
y
x、y
x、y的值,能否求出
a
∗
b
a*b
a∗b?
思路
一开始读错题意了,读成给出a、b,求出x*y
,上来就先WA了一发,ԾㅂԾ,
这要是真在比赛,估计我就被队友生吃了。
运用初中数学原理 (x+y)^2-(x-y)^2==4xy
即可解决。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int main()
{
int a,b;
cin>>a>>b;
cout<<(a*a-b*b)/4<<endl;
}
后话
感谢阅读,希望能对你产生一点用处。
以下台词取自《银魂》第87集:
(十四的内心太细腻了,总悟有点姐控了(●’◡’●))
(87集里有好多十四帅气的镜头,爱了爱了)
(搭嘎,我还是更喜欢我的伊丽莎白(✿◡‿◡))