G题
https://codeforces.com/gym/102215/problem/G
题意
有一天黑客德米特里发现了一个有趣的游戏叫Akinator。这个游戏的规则很简单:玩家想一些名人,阿克熄灯器试着在有限的几个问题中猜出这个人。每个回合熄灯器都会问玩家:“这个人是i1还是i2 ?”还是我?(这里m是问题中的人数,每个问题的人数都不一样)。玩家回答“是”或“不是”,阿克熄灯器将使用获得的信息。一旦阿克熄灯器认识了这个有思想的人,他就说出了答案,赢了。如果熄灯者不能在给定的问题中猜出这个人,他就输了。
熄灯器有k个问题来猜测这个有思想的人。我们事先知道德米特里想到了这n个人中的一个:1,2,…, n的概率为p1 p2…pn。确定Akinator是否能够保证他在k个问题中猜对,如果他能够,他需要的最小平均问题数量是多少。
输入
第一行包含两个整数n和k(1≤k≤n≤100)——可能思考的人数和问题的数量。
第二行包含n个整数a1 a2…an(1≤ai≤1012)概率与ai成正比,即可以计算为。
输出
如果阿克熄灯器不能肯定地猜出有思想的人,输出«No solution»。
否则输出不可约分数——Akinator赢得游戏所需的最小平均问题数。
思路
区间dp。
d[l][r][k]表示第k轮[l,r]区间的最小值。
1 #include2 using namespace std; 3 4 typedef long long LL; 5 const LL INF = 1e15; 6 7 int n,k; 8 9 LL memo[105][105][105]; 10 LL li[105]; 11 12 LL dp(int l, int r, int step){ 13 if(step > k) return INF; 14 if(l==r) return step*li[l]; 15 LL &ret = memo[l][r][step]; 16 if(ret!=-1) return ret; 17 ret = INF; 18 for(int i=l;i ){ 19 ret = min(ret,dp(l,i,step+1)+dp(i+1,r,step+1)); 20 } 21 return ret; 22 } 23 24 int main(){ 25 scanf("%d%d",&n,&k); 26 int tmp = ceil(log2(n)); 27 if(k < tmp){ 28 printf("No solution\n"); 29 return 0; 30 } 31 LL tot = 0LL; 32 memset(memo,-1,sizeof(memo)); 33 for(int i=1;i<=n;i++) scanf("%lld",&li[i]), tot+=li[i]; 34 sort(li+1,li+n+1); 35 LL ans = dp(1,n,0); 36 LL tmp1 = __gcd(ans,tot); 37 ans/=tmp1; 38 tot/=tmp1; 39 printf("%lld/%lld\n",ans,tot); 40 return 0; 41 }
H题
https://codeforces.com/gym/102215/problem/H
题意
一个数组里有0到n一共n+1个数,现在某一个数丢失,让你通过q次询问,每次询问第i个数的二进制数中第j位(从低到高)的结果,找出丢失的数。
思路
交互题。
我们先思考一个问题,如果一个数丢失,他会对整个数组造成什么影响?
首先我们考虑第一轮查询,我们直接查询1到n个数中每个数二进制第一位的结果。
由于原数组是0到n,所以每个数的二进制第一位为1的数量x加起来肯定是(n+1)/2.
设丢失的数为y,
如果查询到的数量b 否则y的第一位为0且y在二进制第一位为0的这些数中. 像这样每轮查询下去,每轮查的次数都为上一次的一半, 也就是总次数q=n+n/2+n/4+n/8+...<=2*n. 最后可以即可确定y的值 具体实现见代码: P1;
9 #define pb push_back
10 #define se second
11 #define fi first
12 #define rs o<<1|1
13 #define ls o<<1
14 #define inf 0x3f3f3f3f3f3f3f3f
15 const int N=1e5+5;
16 set<int>s;
17 int n;
18 int main(){
19 cin>>n;
20 for(int i=1;i<=n;i++){
21 s.insert(i);
22 }
23 set<int> iter it;
24 int res=0,ans=0,b=0;
25 for(int i=0;s.size()>=1;i++){
26 int m=s.size();
27 b=0;
28 set<int>temp;
29
30 for(it=s.begin();it!=s.end();it++){
31 int x=*it;
32 cout<<"? "< https://codeforces.com/gym/102215/problem/J 在绝地武士锦标赛上,n名绝地武士正在互相厮杀。每个绝地武士都有三个标准:力量、敏捷和智慧。当两名绝地武士进行战斗时,获胜的绝地武士至少比他对手的参数高两个参数。例如,带参数的绝地武士(5,9,10)击败带参数的绝地武士(2,12,4),原因是第一个和第三个参数。 西斯有个计划要把一个绝地变成原力的黑暗面。这将给他提供一种强大的技能,允许他在每次战斗前任意设置所有参数,限制是参数应该保持非负整数,并且它们的和不应该改变。 对于每一个绝地武士,决定他能打败多少其他绝地武士转向黑暗势力。 贪心。 把所有人的最小的两个维度值的和的结果存起来从小到大排序,二分查找当前这个人总能力值-1在数组中的位置,输出即可,注意答案要-1,因为自己不能打自己。 P1;
9 #define pb push_back
10 #define se second
11 #define fi first
12 #define rs o<<1|1
13 #define ls o<<1
14 #define inf 0x3f3f3f3f3f3f3f3f
15 const int N=5e5+5;
16 int n,cnt;
17 ll a[N],b[N],d[N];
18 ll c[N];
19 int main(){
20 scanf("%d",&n);
21 for(int i=1;i<=n;i++){
22 scanf("%d%d%d",&a[1],&a[2],&a[3]);
23 c[i]=a[1]+a[2]+a[3]-1;
24 sort(a+1,a+4);
25 ll x=a[1]+a[2];
26 b[++cnt]=x;
27 if(a[3]<=1)d[i]=1;
28 }
29 sort(b+1,b+1+cnt);
30 for(int i=1;i<=n;i++){
31 int k=upper_bound(b+1,b+1+cnt,c[i]-1)-b;
32 if(k==cnt+1)k--;
33 if(b[k]>=c[i])k--;
34 k--;
35 if(d[i])k++;
36 if(i https://codeforces.com/gym/102215/problem/K 有n个卡片,卡片共有RGB三种颜色,现在有两个容器,现在按照给定的顺序发卡片,每次选择把卡片发到一个容器的顶端,要你保证最后两个容器头尾拼接起来后所有的颜色的卡片连在一起。 如果能实现输出YES否则就是NO 模拟。 分两种情况: 1、碰到的第一种卡片和第二种卡片放在同一个容器; 2、碰到的第一种卡片和第二种卡片放在两个不同容器。 P1;
9 #define pb push_back
10 #define se second
11 #define fi first
12 #define rs o<<1|1
13 #define ls o<<1
14 #define inf 0x3f3f3f3f3f3f3f3f
15 const int N=1e5+5;
16 char s[N];
17 int cal(int x){
18 if(x=='R')return 1;
19 else if(x=='G')return 2;
20 return 3;
21 }
22 int a[10],l,r,l1,r1;
23 void work(int t,int len){//第一种情况:首先碰到的两个放在同一堆
24 int x=cal(s[t]);
25 l=x;
26 int id=-1;
27 for(int i=t+1;i https://codeforces.com/gym/102215/problem/L 给定两个相交的圆A和圆B,求在相交区域中能放下的最大的圆的半径和圆心。 其实就是个简单高中数学题。 不难想到内切圆肯定是最大的,然后我们可以先求半径r, 如图: 由于对称性,内切圆D的圆心D肯定在AB上; 设圆A半径为r1,圆B半径为r2,则有: AC=AB-r2; CF=r1-AC; r=CD=CF/2; 求出r后,我们已经知道线段AB和AD=AC+r,求D点直接根据线段比例和向量搞一搞不就出来了。 具体见代码: P1;
9 #define pb push_back
10 #define se second
11 #define fi first
12 #define rs o<<1|1
13 #define ls o<<1
14 #define inf 0x3f3f3f3f3f3f3f3f
15 const int N=1e5+5;
16 double x[3],y[3],r[3];
17 int main(){
18 for(int i=1;i<=2;i++){
19 cin>>x[i]>>y[i]>>r[i];
20 }
21 double dx=x[2]-x[1];
22 double dy=y[2]-y[1];
23 double d=sqrt(dx*dx+dy*dy);
24
25 double g=d-r[2];
26 double ans2=(r[1]-g)/2;
27 g+=ans2;
28 double ans0=x[1]+dx*g/d;
29 double ans1=y[1]+dy*g/d;
30 printf("%.15lf %.15lf %.15lf\n",ans0,ans1,ans2);
31 } 1 #define bug(x) cout<<#x<<" is "<
J题
题意
思路
1 #define bug(x) cout<<#x<<" is "<
K题
题意
思路
1 #define bug(x) cout<<#x<<" is "<
L题
题意
思路
1 #define bug(x) cout<<#x<<" is "<