题目链接: 2020年河南省CCPC大学生程序设计竞赛
A、班委竞选
#include<iostream>
using namespace std;
const int N = 55;
int a[N][N];
int n,m;
int main()
{
cin >> n >> m;
int cnt = 1;
while(n--)
{
int c,t;
cin >> c >> t;
a[c][cnt++] = t;
}
for(int i=1; i<=m; i++)
{
int Max = 0,Maxi = 0;
for(int j=1; j<cnt; j++)
{
if(Max < a[i][j])
{
Max = a[i][j];
Maxi = j;
}
}
cout << Maxi << " ";
}
return 0;
}
C、我得重新集结部队
注意用 long long
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
struct node
{
int type; //狂躁者2 异虫1
LL x,y;
LL h;
LL atk;
LL r;
int liu; //0留在战场,2死亡
}aa[3000];
LL dist(int x1,int y1,int x2,int y2)
{
return ((LL)(x1-x2)*(x1-x2)+(LL)(y1-y2)*(y1-y2));
}
int main()
{
int n;
cin >> n;
int cnt = -1;
while(n--)
{
cnt++;
int t;
cin >> t;
if(t == 1) //异虫
{
aa[cnt].type = 1;
cin >> aa[cnt].x >> aa[cnt].y >> aa[cnt].h;
}
else //狂躁者
{
aa[cnt].type = 2;
cin >> aa[cnt].x >> aa[cnt].y >> aa[cnt].atk >> aa[cnt].r;
LL Min = 1e18;
int Mini = -1;
for(int i=0; i<=cnt; i++)
{
if(aa[i].type==1 && aa[i].h>0)
{
LL d = dist(aa[i].x,aa[i].y,aa[cnt].x,aa[cnt].y);
if(d < Min )
{
Min = d;
Mini = i; //最近的异虫
}
}
}
if(Mini == -1) continue;
aa[cnt].x = aa[Mini].x,aa[cnt].y = aa[Mini].y; //跳到最近的异虫位置
for(int i=0; i<=cnt; i++)
{
if(aa[i].type==1 && aa[i].h>0 && dist(aa[cnt].x,aa[cnt].y,aa[i].x,aa[i].y)<=aa[cnt].r*aa[cnt].r)
{
aa[i].h -= 3*aa[cnt].atk; //攻击异虫
if(aa[i].h>0) //狂躁者离开战场
{
aa[cnt].liu = 2;
}
else //异虫死亡
{
aa[i].h = 0;
}
}
}
}
}
for(int i=0; i<=cnt; i++)
{
if(aa[i].type==1) //chong
{
if(aa[i].h>0) cout << "Yes" << endl;
else cout << "No" << endl;
}
else //kuang
{
if(aa[i].liu==2) cout<<"No"<<endl;
else cout << "Yes"<<endl;
}
}
return 0;
}
E、发通知
当一个区间是 [l,r] 时,经过 l 时,可以接到通知的人数+1,到 r + 1点时,这个同学不能接到通知了,可以接到通知的人数-1。所以,一个区间内我们只需要考虑两个点 :l 和 r + 1。当到 l 时,我们异或w,人数+1,当到 r+1 时,我们再异或w,人数-1。
为什么到 r+1 时还要异或w?
因为异或的性质 :A ^ w ^ w = A
,当到 r+1 时,我们需要把之前在 l 点异或的 w 给撤销掉(也就是恢复到异或前),所以在 r+1 点再异或w就行了。
初始:A
l点:A ^ w
r+1点:A ^ w ^ w = A
#include<iostream>
#include<map>
using namespace std;
typedef pair<int,int> PII;
map<int,PII> m; //端点:{w,人数}
int n,k;
void add(int x,int w,int cnt)
{
m[x].first ^= w;
m[x].second += cnt;
}
int main()
{
cin >> n >> k;
while(n--)
{
int l,r,w;
cin >> l >> r >> w; //左端点、右端点、愉悦度
add(l,w,1); //l点能收到通知的人数+1
add(r+1,w,-1); //r+1这个点已经出l~r的区间了,人数-1
}
int res = -1,num = 0,t = 0;
for(auto x:m)
{
t ^= x.second.first;
num += x.second.second;
if(num >= k)
res = max(res,t);
}
cout << res;
}
I、太阳轰炸
击中碎片的概率 p =
(
R
1
+
r
)
2
R
2
2
\frac {(R~1~+r) ^2} {R~2~ ^2}
R 2 2(R 1 +r)2,未击中的概率为 q =
R
2
2
−
(
R
1
+
r
)
2
R
2
2
\frac {R~2~^2-(R~1~+r)^2} {R~2~ ^2}
R 2 2R 2 2−(R 1 +r)2。
若想摧毁碎片,那么击中的次数至少为 k = ⌈ h a \frac {h} {a} ah⌉
摧毁碎片的概率 x = C(n,k) * pk * q n-k + C(n,k+1) * pk+1 * qn-k-1 + … + C(n,n) * pn * q0 ,x符合二项分布。
注意:(
A
b
\frac {A} {b}
bA) % mod = A * b’ % mod (b’指b的逆元 求逆元:快速幂求逆元)
求组合数:使用博客内求组合数II方法求解
注意使用long long
#include<iostream>
using namespace std;
typedef long long LL;
LL n,r1,r2,r,a,h;
const int p = 1e9 + 7,N = 5e6 + 5;
LL fact[N],infact[N];
LL qmi(LL a,int k)//快速幂
{
a = a % p;
LL res = 1;
while(k)
{
if(k&1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
LL C(int a,int b)
{
return fact[a] * infact[b] % p * infact[a-b] % p;
}
int main()
{
// cin >> n >> r1 >> r2 >> r >> a >> h;
scanf("%lld%lld%lld%lld%lld%lld",&n,&r1,&r2,&r,&a,&h);
int k;
if(h%a == 0)
k = h/a;
else k = h/a + 1; //上取整
if(k>n) //k最大到n,>n时不可能,概率为0
{
cout<<"0";
return 0;
}
if(r1+r>=r2) //概率最大为1
{
cout<<"1";
return 0;
}
fact[0] = infact[0] = 1;
for(int i=1; i<=n; i++) //预处理出阶乘、阶乘的逆元
{
fact[i] = (LL)fact[i-1] * i % p;
infact[i] = (LL)infact[i-1] * qmi(i,p-2) % p;
}
LL res = 0;
LL rn = qmi(r2 * r2 % p,p-2); //r2的逆元
LL pp = (r1+r)*(r1+r) % p * rn % p; //即概率p
LL qq = (r2*r2%p - (r1+r)*(r1+r)%p + p) % p * rn % p;//即概率q
LL pk = qmi(pp,k); //p^k
LL qnk = qmi(qq,n-k); //q^(n-k)
for(int i=k; i<=n; i++)
{
res = (res + (C(n,i) * pk % p * qnk % p) % p) % p;
pk = pk * pp % p;
qnk = qnk * qmi(qq,p-2) % p;
}
printf("%lld",res);
}