问题 D: 田忌赛马
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
他是一匹棕色的马。他在奔跑,和一群马一起奔跑。
这是那片古老大地上流传着的一个故事,关于马的故事。马之故事,以鞍为墨。
现在,田忌又一次与人赛马。不过不同的是,赛制发生了变化。田忌与对手决定一场定胜负。双方都不能选择自己参赛的马,他们用于一决高下的马将在自己的所有马中随机产生。每一匹马都有一个能力值。能力值较高的马获胜。当两匹马能力值相同时这场比赛被视为平局。
运筹帷幄的田忌不想在未知中等待结果的到来,所以他想知道自己获胜的概率是多少。
输入
第1行一个正整数T,表示数据组数。
对于每组数据,第1行两个正整数N,M,分别表示田忌和对手拥有的马的数量。
第2行N个正整数,第i个正整数Ai表示田忌第i匹马的能力值。
第3行M个正整数,第i个正整数Bi表示对手第i匹马的能力值。
输出
共T行对每组数据,一行一个分数,“x/y”(不含引号) ,表示田忌获胜的概率(最简分数) 。
样例输入 Copy
1
3 5
4 3 7
1 9 4 6 10
样例输出 Copy
1/3
提示
样例解释
为方便解释,我们称一组随机选马为二元组(x,y)
,x,y分别代表田忌和对手的马的能力值。
当二元组为(4,1)、(3,1)、(7,1)、(7,4)、(7,6)时,田忌获胜,共5种。
随机选马共有3×5=15种方法。
所以田忌获胜的概率为5/15,化为最简分数为1/3。
对于100%的数据,1≤N,M≤40000;1≤Ai,Bi<109,1≤T≤5
实在有点坑,注意避免一些重复数据的计算。//cnt,其实也可以优先队列,不过我没试。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int a[40005],b[40005],cnt[400005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,kk=0;
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int j=1;j<=m;j++)
scanf("%d",b+j);
sort(a+1,a+1+n);
sort(b+1,b+1+m);
int j=1;
for(int i=1;i<=n;i++)
{
cnt[i]+=cnt[i-1];
for(;j<=m;)
{
if(a[i]>b[j]) cnt[i]++,j++;
else break;
}
kk+=cnt[i];
}
int ans=kk;
int sum=n*m;
// printf("%d/%d\n",ans,sum);
while(kk)
{
int temp=kk;//sum%cnt
kk=sum%kk;
sum=temp;
}
printf("%d/%d\n",ans/sum,n*m/sum);
}
return 0;
}
问题 A: 埃匹希斯水晶
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
⼤家都知道,卡德加是⼀个神奇的法师。
有⼀天,他发现了⼀种可以作⽤在埃匹希斯⽔晶上的魔法:在左右两个祭坛上放⼀定量的⽔晶,然后施放⼀个法术,左边⼀堆的⽔晶数量会变成原来两个祭坛上⽔晶之和,右边⼀堆会变成两个祭坛上⽔晶数量之差。
卡德加现在有两堆⽔晶,分别有A个和B个。他打算集中精⼒连续释放N次法术,但不知道最后能拿到多少⽔晶,于是他找到了要塞指挥官(就是你了)。
输入
三个整数A,B,N(A,B≤109,N≤1018),表⽰祭坛上刚开始的⽔晶数,和法术的释放次数。
输出
两个数,祭坛上最后的⽔晶数。输出模(109+7)。
样例输入 Copy
1 2 3
样例输出 Copy
6 2
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mod=1e9+7;
int main()
{
ll a,b,n;
cin>>a>>b>>n;
if(a>=b)
{
ll cnt=n/2,temp=1;
while(cnt--)
{
temp*=2;
temp%=mod;
}
if(n%2==1)
{
printf("%lld %lld",temp*(a+b)%mod,temp*(a-b)%mod);
}
if(n%2==0)
{
printf("%lld %lld",temp*a%mod,temp*b%mod);
}
}
else
{
ll cnt=n/2,temp=1;
while(cnt--)
{
temp*=2;
temp%=mod;
}
if(n%2==1)
{
printf("%lld %lld",temp*(a+b)%mod,temp*(b-a)%mod);
}
if(n%2==0)
{
printf("%lld %lld",temp*b%mod,temp*a%mod);
}
}
return 0;
}
/**************************************************************
Problem: 15411
User: 2019UPC110
Language: C++
Result: 正确
Time:267 ms
Memory:2024 kb
****************************************************************/
问题 B: 要塞任务
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
你的要塞⾥有N名随从,每名随从有⼀个战⽃⼒值Ai,不同随从的战⽃⼒可以相同,且永远不超过N。⼀个要塞任务需要恰好M个随从参与。
要塞任务的奖励取决于随从们配合的程度。(显⽽易见地),M个随从的联合战⽃⼒A为它们战⽃⼒的最⼤公约数,⽽任务的奖励分数定义为ϕ(A)。
求最⼤可能的奖励分数。
输入
本题有多组数据,第⼀⾏为数据组数T(T≤10)。
接下来每组数据有两⾏,第⼀⾏两个整数N,M,第⼆⾏N个整数Ai(N,M,Ai≤100000)。
输出
最多的奖励分数。
样例输入 Copy
1 5 2 1 4 6 9 12
样例输出 Copy
2
提示
样例解释:派出编号为6和12的随从,联合战⽃⼒为3,奖励分数2。
https://blog.csdn.net/sadsummerholiday/article/details/82825252
https://www.cnblogs.com/Droyal/p/7418611.html
欧拉筛,这个处理很棒
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int vis[400005],prim[400005],oul[400005],num[100005],cnt;
void init()
{
oul[1]=1;//1是1
for(int i=2; i<=100000; i++)
{
if(vis[i]==0)
{
prim[++cnt]=i;
oul[i]=i-1;//其前面有i-1个互质//质数而言
}
for(int j=1; prim[j]*i<=100000; j++)
{
vis[prim[j]*i]=1;
if(i%prim[j]==0)
break;//*
}
}
for(int i=2; i<=100000; i++)
{
if(vis[i])
{
oul[i]=i;
int tmp=i;
for(int j=1; j<=cnt&&tmp>1; j++)
{
if(i%prim[j]==0)
{
oul[i]=oul[i]*(prim[j]-1)/prim[j];
while(tmp%prim[j]==0)
tmp/=prim[j];
}
if(prim[j]*2>i)
break;
}
}
}
}
int main()
{
int t,n,m,a,maxn=0;
cin>>t;
init();//
while(t--)
{
cin>>n>>m;
int ans=0;
memset(num,0,sizeof(num));
for(int i=1; i<=n; i++)
{
cin>>a;
maxn=max(maxn,a);
num[a]++;
}
for(int i=1; i<=maxn; i++)
{
int tmp=0;
for(int j=i; j<=maxn; j+=i)
{
tmp+=num[j];
}
if(tmp>=m)
ans=max(ans,oul[i]);
}
cout<<ans<<endl;
}
return 0;
}