zoukankan      html  css  js  c++  java
  • 2019, XII Samara Regional Intercollegiate Programming (G、H、J、K、L题解)

    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 #include<bits/stdc++.h>
     2 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<r;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
    ");
    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
    ",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<x,y的第一位为1且y在二进制第一位为1的这些数中,

    否则y的第一位为0且y在二进制第一位为0的这些数中.

    像这样每轮查询下去,每轮查的次数都为上一次的一半,

    也就是总次数q=n+n/2+n/4+n/8+...<=2*n.

    最后可以即可确定y的值

    具体实现见代码:

     1 #define bug(x) cout<<#x<<" is "<<x<<endl;
     2 #define IO std::ios::sync_with_stdio(0);
     3 #include <bits/stdc++.h>
     4 #define iter ::iterator
     5 using namespace  std;
     6 typedef long long ll;
     7 typedef pair<ll,ll>P;
     8 typedef pair<P,P>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<<"? "<<x<<" "<<i<<endl;
    33             cout.flush();
    34             cin>>res;
    35             if(res){
    36                 temp.insert(x);
    37                 b++;
    38             }
    39         }
    40         if(b<(m+1)/2){
    41             ans+=(1<<i);
    42             s=temp;
    43         }
    44         else{
    45             for(it=temp.begin();it!=temp.end();it++){
    46                 int x=*it;
    47                 s.erase(x);
    48             }
    49         }
    50         
    51     }
    52     cout<<"! "<<ans<<endl;
    53     cout.flush();
    54 }

    J题

    https://codeforces.com/gym/102215/problem/J

    题意

    在绝地武士锦标赛上,n名绝地武士正在互相厮杀。每个绝地武士都有三个标准:力量、敏捷和智慧。当两名绝地武士进行战斗时,获胜的绝地武士至少比他对手的参数高两个参数。例如,带参数的绝地武士(5,9,10)击败带参数的绝地武士(2,12,4),原因是第一个和第三个参数。

    西斯有个计划要把一个绝地变成原力的黑暗面。这将给他提供一种强大的技能,允许他在每次战斗前任意设置所有参数,限制是参数应该保持非负整数,并且它们的和不应该改变。

    对于每一个绝地武士,决定他能打败多少其他绝地武士转向黑暗势力。

    思路

    贪心。

    把所有人的最小的两个维度值的和的结果存起来从小到大排序,二分查找当前这个人总能力值-1在数组中的位置,输出即可,注意答案要-1,因为自己不能打自己。

     1 #define bug(x) cout<<#x<<" is "<<x<<endl;
     2 #define IO std::ios::sync_with_stdio(0);
     3 #include <bits/stdc++.h>
     4 #define iter ::iterator
     5 using namespace  std;
     6 typedef long long ll;
     7 typedef pair<ll,ll>P;
     8 typedef pair<P,P>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<n)printf("%d ",k);
    37         else printf("%d
    ",k);
    38     }
    39 }

    K题

    https://codeforces.com/gym/102215/problem/K

    题意

    有n个卡片,卡片共有RGB三种颜色,现在有两个容器,现在按照给定的顺序发卡片,每次选择把卡片发到一个容器的顶端,要你保证最后两个容器头尾拼接起来后所有的颜色的卡片连在一起。

    如果能实现输出YES否则就是NO

    思路

    模拟。

    分两种情况:

    1、碰到的第一种卡片和第二种卡片放在同一个容器;

    2、碰到的第一种卡片和第二种卡片放在两个不同容器。

      1 #define bug(x) cout<<#x<<" is "<<x<<endl;
      2 #define IO std::ios::sync_with_stdio(0);
      3 #include <bits/stdc++.h>
      4 #define iter ::iterator
      5 using namespace  std;
      6 typedef long long ll;
      7 typedef pair<ll,ll>P;
      8 typedef pair<P,P>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<len;i++){
     28         x=cal(s[i]);
     29         if(x==l1){
     30             id=i;
     31             r1=r=x;
     32             break;
     33         }
     34         if(x!=l){
     35             id=i;
     36             r1=r=x;
     37             break;
     38         }
     39     }
     40     if(id==-1){
     41         printf("YES
    ");
     42         exit(0);
     43     }
     44     int flag=0;
     45     for(int i=id+1;i<len;i++){
     46         x=cal(s[i]);
     47         if(x==l||x==r)continue;
     48         if(r1==l1){
     49             flag++;
     50             break;
     51         }
     52         id=i;
     53         r=x;
     54         break;
     55     }
     56     if(!flag){
     57         int i;
     58         for(i=id+1;i<len;i++){
     59             x=cal(s[i]);
     60             if(!(x==l||x==r))break;
     61         }
     62         if(i==len){
     63             printf("YES
    ");
     64             exit(0);
     65         }
     66     }
     67 
     68 }
     69 int main(){
     70     scanf("%s",s);
     71     int len=strlen(s);
     72     if(len<=3){
     73         printf("YES
    ");
     74         return 0;
     75     }
     76     int x=cal(s[0]);
     77     l1=l=x;
     78     int tl=l;
     79     a[x]++;
     80     int p=0;
     81     while(p<len){
     82         if(cal(s[p])!=x)break;
     83         p++;
     84     }
     85     if(p==len){
     86         printf("YES
    ");
     87         return 0;
     88     }
     89     work(p,len);
     90     l1=l=tl;
     91     x=cal(s[p]);
     92     r1=r=x;   //第二种情况:首先碰到的两个分别放在两堆
     93     a[x]++;
     94     int id=-1;
     95     for(int i=p;i<len;i++){
     96         x=cal(s[i]);
     97         if(!a[x]){
     98             id=i;
     99             break;
    100         }
    101     }
    102     if(id==-1){
    103         printf("YES
    ");
    104         return 0;
    105     }
    106     int k=cal(s[id]);
    107     int flag=0;
    108     for(int i=id+1;i<len;i++){
    109         x=cal(s[i]);
    110         if(a[x]){
    111             flag++;
    112             id=i;
    113             if(x==l){
    114                 r=k;
    115             }
    116             else l=k;
    117             break;
    118         }
    119     }
    120     if(!flag){
    121         printf("YES
    ");
    122         return 0;
    123     }
    124     int flag1=0;
    125     for(int i=id+1;i<len;i++){
    126         x=cal(s[i]);
    127         if(x==l||x==r)continue;
    128         flag1++;
    129         if(l1==x)r=x;
    130         else if(r1==x)l=x;
    131         id=i;
    132         break;
    133     }
    134     for(int i=id+1;i<len;i++){
    135         x=cal(s[i]);
    136         if(!(x==l||x==r)){
    137             printf("NO
    ");
    138             return 0;
    139         }
    140     }
    141     printf("YES
    ");
    142 }

    L题

    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点直接根据线段比例和向量搞一搞不就出来了。

    具体见代码:

     1 #define bug(x) cout<<#x<<" is "<<x<<endl;
     2 #define IO std::ios::sync_with_stdio(0);
     3 #include <bits/stdc++.h>
     4 #define iter ::iterator
     5 using namespace  std;
     6 typedef long long ll;
     7 typedef pair<ll,ll>P;
     8 typedef pair<P,P>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
    ",ans0,ans1,ans2);
    31 }
  • 相关阅读:
    AIO5岗位桌面主页【我的收藏夹】只显示8行,怎样增加显示行?
    已设置了参考编号的编码规则定义,但是新增单据的时候,没有出来自动编号是什么原因?
    10个TWaver 网页3D可视化精彩案例
    HTML5大数据可视化效果(二)可交互地铁线路图
    无插件纯web 3D机房 (第四季:大型园区、地球仪效果和其他扩展应用)
    一款基于HTML5的Web 3D开发工具
    Legolas工业自动化平台入门(三)交互事件响应动作
    Legolas工业自动化平台入门(二)数据响应动作
    Legolas工业自动化平台入门(一)搭建应用
    Legolas工业自动化平台案例 —— 水源地自动化监控系统
  • 原文地址:https://www.cnblogs.com/ccsu-kid/p/11102610.html
Copyright © 2011-2022 走看看