目录
A. A Greeting from Qinhuangdao
E. Exam Results
F. Friendly Group
G. Good Number
K. Kingdom's Power
题意:有r个红球,b个蓝球,取两次,求两次都是红球的概率;
思路:答案即为c[2][r]/c[2][r+b]。
void solve() {
int r,b,p;
cin>>r>>b;
int k1=r*(r-1),k2=(b+r)*(b+r-1);
p=__gcd(k1,k2),k1/=p,k2/=p;
cout<<"Case #"<<++t<<": "<
题意:每个人的成绩有两种可能(ai或bi),设这次考试最高成绩为x,定义及格线为百分之x*p,问最多可以有多少人及格
思路:尺取,先将所有人的成绩都存入数组排个序,然后尺取合法的区间,换成暴力的思想来说,就是枚举最高分数,具体实现见代码注释。
struct ss {
int x,y;
} a[3*maxn];
int st[3*maxn];
bool cmp(ss a,ss b) {
return a.xmp;
int n,k;
cin>>n>>k;
FOR(1,n) {
cin>>a[i].x>>a[n+i].x;//a[i].x表示成绩,a[i].y表示这是第i个人的成绩
a[i].y=i,a[n+i].y=i;
st[i]=st[n+i]=0;
}
sort(a+1,a+2*n+1,cmp);
int l=1,r=0,now=0;
int ans=-inf,f=0;
while(r<2*n) {
r++;
if(st[a[r].y]==0)now++;//若还没选过这个人的成绩,则区间内的人数数量加一
st[a[r].y]++;
if(now==n)f=1;//至少先选满n个人,再开始尺取
while(f&&a[l].x*100
题意:给定n个学生,其中有m对好朋友(x,y),老师要挑选一些学生去比赛,设定这群学生友谊值初始为0,如果一对好朋友都被挑选到,群体友谊值+1,如果一对好朋友当中只有其中一人被选中,群体友谊值−1,如果有k个学生参加了比赛,群友谊值−k,问挑选出学生群最大友谊值是多少。
思路:可以发现,如果选了一个人,这个人对于答案的贡献为-1,若选了这个人的朋友, 这个人对于答案的还是贡献为-1,并不会改变,但是若这个人的朋友与朋友之间是朋友,那么答案就会增加。所以对于一个人,要么不选他,并且也不选他的朋友,要么选他,并且将他的朋友也选择了,对于这个问题我们可以利用并查集,记录一个连通块里的朋友对数与朋友人数,若朋友对数大于了朋友人数,我们就选它。
int find(int x){
if(x==pre[x])return x;
return pre[x]=find(pre[x]);
}
void solve() {
int n,m,ans=0,x,y;
cin>>n>>m;
FOR(1,n)pre[i]=i,sum[i]=0,num[i]=1;//sum存朋友对,num存人数
while(m--){
cin>>x>>y;
int fx=find(x),fy=find(y);
if(fx!=fy){
sum[fx]+=sum[fy]+1;
num[fx]+=num[fy];
pre[fy]=fx;
}
else sum[fx]++;//若祖先相同则这个连通块的朋友对数加一
}
FOR(1,n) if(find(i)==i)ans+=max(0ll,sum[i]-num[i]);//答案加上朋友对大于人数的数量
cout<<"Case #"<<++t<<": "<
题意:如果一个数字是Good Number,当且仅当x开k次方后,能整除x。即x能整除以(x开k次方后的数)现在给出n和k,求1到n之中Good Number 的个数。
思路:若一个数开k次方后等于x,则该数的范围为[x^k,x^(k+1)-1],则这个区间内只要是x的倍数的数都可以,又因为[1,x^k-1]中x的倍数的个数为⌊(x^k-1)/x⌋,[1,x^(k+1)-1]中x的倍数的个数为⌊x^(k+1)-1/x⌋,所以每个区间对于答案的贡献为⌊x^(k+1)-1/x⌋-⌊(x^k-1)/x⌋。
int qkp(int a,int b) {
int sum=1;
while(b) {
if(b&1)sum*=a;
b>>=1;
a*=a;
}
return sum;
}
int t=0;
void solve() {
int n,k,ans=0;
cin>>n>>k;
if(k>30||k==1) {
cout<<"Case #"<<++t<<": "<
题意:根节点1上有无数个军队,每一次国王都可以指挥一支军队向相邻一个节点运动,问多少次占领所有的节点。
思路:考虑行进的方案,我们必然是先深度最浅的子节点,而对于深度更深的子节点,我们只有两种遍历方案:
1.从根节点直接跑过来
2.从旁边的叶子节点绕过来
最后我们只需先跑一遍dfs,根据深度排序下叶子节点,然后再跑一遍dfs根据上述方案两者取min即可。
void dfs(int x) {
for(auto k:e[x]) {
dep[k]=dep[x]+1;//dep存深度
dfs(k);
maxx[x]=max(maxx[x],maxx[k]+1);//maxx存子节点的最深深度
}
}
bool cmp(int x,int y) {
return maxx[x]>n;
FOR(0,n)dep[i]=maxx[i]=pre[i]=0,e[i].clear();
FOR(2,n)cin>>x,e[x].push_back(i);
dfs(1);
FOR(1,n)sort(e[i].begin(),e[i].end(),cmp);
dfs2(1);
cout<<"Case #"<<++t<<": "<