Gym - 100384 Winter Programming School 2014, Kharkov The 23-d of the Fabruary 2014. (day 9), junior

这篇博客详细介绍了2014年Kharkov冬季编程学校第9天的Junior组问题,包括Maximal Difference、Triangle Construction、Beautiful Patterns等题目的题意、解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem B. Maximal Difference (Junior)

题意:给你一个n,让你找出n位数中各个位数相加相等且差值最大的值。 比如n=2就是91和19,所以答案就是72

题解:直接一个个算出来或者找规律,n=2就是91和19,n=3就是910和109,n=4就是9910和1099。

代码:

#include<cstdio>
int n;
int main(){
    scanf("%d",&n);
    switch(n){
        case 1: printf("0\n");break;
        case 2: printf("72\n");break;
        case 3: printf("801\n");break;
        case 4: printf("8811\n");break;
        case 5: printf("89001\n");break;
        case 6: printf("898101\n");break;
        case 7: printf("8990001\n");break;
        case 8: printf("89981001\n");break;
        case 9: printf("899900001\n");break;
        case 10: printf("8999810001\n");break;
    }
    return 0;
}

Problem D. Triangle Construction (Junior)

题意:给你三角形的三边,若不能成为三角形则输出Impossible ,否则输出三个点的坐标(任意)。

题解:固定两个点在x轴上,然后求出一个角的角度,用三角形正余弦定理就能搞定了= =

代码:

#include<cstdio>
#include<cmath>
const double eps=1e-7;
struct node{
    double x,y;
}e[3];
double a,b,c;
double s;
int main(){
    scanf("%lf%lf%lf",&a,&b,&c);
    if(a+b-c<=eps||a+c-b<=eps||b+c-a<=eps){
        printf("Impossible\n");
        return 0;
    }
    e[0].x=e[0].y=0;
    e[1].x=a;
    e[1].y=0;
    double s=acos((b*b+a*a-c*c)/(double)(2*a*b));
    printf("%lf %lf\n",e[0].x,e[0].y);
    printf("%lf %lf\n",e[1].x,e[1].y);
    printf("%lf %lf\n",a-b*cos(s),b*sin(s));
    return 0;
}

Problem F. Beautiful Patterns (Junior)

题意:给你一个n*m的地板和k块已经知道颜色的单元地板,若是这个地板在所有的2*2的块中都有3个白地板和1个黑地板或3个黑地板和1个白地板,则这个n*m的地板则为beautiful,求有多少种方法能使得这个n*m的地板为beautiful

题解:由于n,m较小,因此我们先枚举第一行的所有情况,最多有1024种情况(要排除不行的,题目给你是白色的,你却用黑色填充这种情况)。然后对于下一行,我们假设第一块是白色或者黑色的可能,然后从第二块开始枚举,就可以得到精确的这一行各块的颜色了,我们用mp[i][j]记录方法到第i行第j种方法的方案数,最后我们会得到这么一个递推公式:mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod。最后ans=∑mp[n-1][0->2^(m-1)]

代码:

#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
ll n,m,k,x,y,z,flag,ss;
ll mp[15][1111],mmp[15][15];
ll s[15][15],ans,sa[15];
struct node{
    ll x,y,z;
}e[105];
int main(){
    scanf("%lld%lld%lld",&n,&m,&k);
    for(ll i=0;i<=10;i++)
        for(ll j=0;j<=10;j++)  s[i][j]=-1;
    for(ll i=0;i<k;i++){
        scanf("%lld%lld%lld",&x,&y,&z);
        s[x-1][y-1]=z;
    }
    sa[0]=1;
    for(ll i=1;i<=10;i++)   sa[i]=sa[i-1]*2;
    for(ll i=0;i<sa[m];i++){
        flag=1;
        for(ll j=0;j<m;j++){
            if(s[0][j]!=-1&&((i>>j)%2)!=s[0][j]){
                flag=0;
                break;
            }
        }
        if(flag)    mp[0][i]=1;
    }
    for(ll i=1;i<n;i++){
        for(ll j=0;j<sa[m];j++){
            if(mp[i-1][j]==0)   continue;
            for(ll k=0;k<m;k++)    mmp[i-1][k]=(j>>k)%2;
            mmp[i][0]=0;    //最前面为0的情况
            for(ll k=1;k<m;k++){
                ll a0=0,a1=0;
                if(mmp[i][k-1]==0)    a0++;
                if(mmp[i-1][k-1]==0)    a0++;
                if(mmp[i-1][k]==0)    a0++;
                if(a0==0||a0==2)    mmp[i][k]=0;
                else mmp[i][k]=1;
            }
            flag=1;
            for(ll k=0;k<m;k++){
                if(s[i][k]!=-1&&s[i][k]!=mmp[i][k]){
                    flag=0;
                    break;
                }
            }
            if(flag){
                ss=0;
                for(ll k=m-1;k>=0;k--) ss=ss*2+mmp[i][k];
                mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod;
            }


            mmp[i][0]=1;    //最前面为1的情况
            for(ll k=1;k<m;k++){
                ll a0=0,a1=0;
                if(mmp[i][k-1]==0)    a0++;
                if(mmp[i-1][k-1]==0)    a0++;
                if(mmp[i-1][k]==0)    a0++;
                if(a0==0||a0==2)    mmp[i][k]=0;
                else mmp[i][k]=1;
            }
            flag=1;
            for(ll k=0;k<m;k++){
                if(s[i][k]!=-1&&s[i][k]!=mmp[i][k]){
                    flag=0;
                    break;
                }
            }
            if(flag){
                ss=0;
                for(ll k=m-1;k>=0;k--) ss=ss*2+mmp[i][k];
                mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod;
            }
        }
    }

    for(ll i=0;i<sa[m];i++) ans=(ans+mp[n-1][i])%mod;
    printf("%lld\n",ans);
    return 0;
}

Problem H. String without repetitions (Junior)

题意:让你求一个长度为n的字符串,长度为k的任意两个相邻子串都不能相同(k为任意),且字典序最小。

题解:由于任意两个相邻子串都不能相同,所以我们要分割这个串,因此我们能先把1的倍数的位置先放入a,然后在2的倍数的位置放入b,再在4的倍数的位置放入c,按照这个规律即可求出这个长度为n的字符串。

代码:

#include<cstdio>
#include<cstring>
int n,a[30],s;
char st[4000005];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)   st[i]='a';
    a[0]=1;
    for(int i=1;i<30;i++){
        a[i]=a[i-1]*2;
        if(a[i]>=n){
            s=i;break;
        }
    }
    for(int i=1;i<=s;i++){
        for(int j=a[i];j<=n;j+=a[i]){
            st[j]='a'+i;
        }
    }
    printf("%s\n",st+1);
    return 0;
}

Problem J. Beans gathering (Junior)

题意:给你n个盒子和每个盒子中豆子的个数,第i个可以将i的倍数个豆子放入第i-1个,问你最后能不能把所有豆子放到第0个盒子

题解:从后向前for一遍就可以了= =,如果遇到一个盒子的豆子无法被i除尽,则输出no,否则将这些豆子放到第i-1个盒子。

代码:

#include<cstdio>
#include<cstring>
int n,a[30],s;
char st[4000005];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)   st[i]='a';
    a[0]=1;
    for(int i=1;i<30;i++){
        a[i]=a[i-1]*2;
        if(a[i]>=n){
            s=i;break;
        }
    }
    for(int i=1;i<=s;i++){
        for(int j=a[i];j<=n;j+=a[i]){
            st[j]='a'+i;
        }
    }
    printf("%s\n",st+1);
    return 0;
}

Problem L. Reverse beans gathering (Junior)

题意:给你n个豆子,让你放在各个盒子里,移动方法如上题,问你输出最小字典序的豆子放法(最小字典序定义看题)

题解:将n个豆子从第0个盒子到1,2,3模拟,直到豆子用完为止即可。
例: 7个豆子。
7%1==0,所以变成0 7
7%2==0,所以变成0 1 6
6%3==0,所以变成0 1 0 6
6%4==2,所以变成0 1 0 2 4 到此豆子用完。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,a[100005],flag=1;
int main(){
    scanf("%lld",&n);
    for(ll i=0;i<=n;i++)    scanf("%lld",&a[i]);
    for(ll i=n;i>0;i--){
        if(a[i]%i==0)   a[i-1]+=a[i];
        else{
            flag=0;
            break;
        }
    }
    if(flag)    printf("Yes\n");
    else printf("No\n"); 
    return 0;
} 

Problem N. Equation (Junior)

题意:给你多项式的系数,求满足等式的最小x

题解:这题可以转化为,是否存在x满足多项式是p*2的倍数,那就可以枚举x,由于循环节是2014*2014,所以最多循环2014*2014次。

代码:

#include<bits/stdc++.h>
typedef long long ll;
ll n,a[25],p,flag,ans;
int main(){
    scanf("%lld%lld",&p,&n);
    for(ll i=n;i>=0;i--)   scanf("%lld",&a[i]);
    ll pp=p*p;
    for(ll i=0;i<=pp;i++){
        ll sum=0,s=1;
        for(ll j=0;j<=n;j++){
            sum=(sum+s*a[j])%pp;
            s=(s*i)%pp;
        }
        if(sum==0){
            ans=i;
            flag=1;
            break;
        }
    }
    if(flag)    printf("%lld\n",ans);
    else printf("-1\n");
    return 0;
}

Problem P. Competition (Junior)

题意:给你两个数列,他们的数字是1->2*n,每个数都不相同,然后每次第一个人从第一个数列选一个数,第二个人从第二个数列选一个数,问第二个人能赢的次数最多是多少次。

题解:把第二个人的数放入数组,然后贪心即可(不会的可以去看看田忌赛马)

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[400005],x,sum,ans;
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++)    scanf("%d",&x);
    for(int i=0;i<n;i++){
        scanf("%d",&x);
        a[x]=1;
    }
    for(int i=1;i<=2*n;i++){
        if(a[i]==0) sum++;
        else{
            if(sum>0){
                ans++;
                sum--;
            }   
        }
    }
    printf("%d\n",ans);
    return 0;
} 

Problem R. The incircle (Junior)

题意:给你一个凸多边形,求内含的圆的最大半径。

题解:半平面交模板题,首先二分边向内延伸的长度,对于每个长度,我们通过半平面交,判断是否存在内核,若存在内核,则存在该半径(也就是向内延伸的长度),增大半径,反之亦然。 代码:

#include<iostream>  
#include <stdio.h>  
#include <math.h>  
#define eps 1e-8  
using namespace std;  
const int MAXN=105;  
int m;  
double r;  
int cCnt,curCnt;//此时cCnt为最终切割得到的多边形的顶点数、暂存顶点个数  
struct point  
{  
    double x,y; 
};  
point points[MAXN],p[MAXN],q[MAXN];//读入的多边形的顶点(顺时针)、p为存放最终切割得到的多边形顶点的数组、暂存核的顶点  

void getline(point x,point y,double &a,double &b,double   &c){//两点x、y确定一条直线a、b、c为其系数  
    a = y.y - x.y;  
    b = x.x - y.x;  
    c = y.x * x.y - x.x * y.y;  
}  
void initial(){  
    for(int i = 1; i <= m; ++i)p[i] = points[i];  
    p[m+1] = p[1];  
    p[0] = p[m];  
    cCnt = m;//cCnt为最终切割得到的多边形的顶点数,将其初始化为多边形的顶点的个数  
}  
point intersect(point x,point y,double a,double b,double c){//求x、y形成的直线与已知直线a、b、c、的交点  
    double u = fabs(a * x.x + b * x.y + c);  
    double v = fabs(a * y.x + b * y.y + c);  
    point pt;  
    pt.x=(x.x * v + y.x * u) / (u + v);  
    pt.y=(x.y * v + y.y * u) / (u + v);  
    return  pt;  
}  
void cut(double a,double b ,double c){  
    curCnt = 0;  
    for(int i = 1; i <= cCnt; ++i){  
        if(a*p[i].x + b*p[i].y + c >= 0)q[++curCnt] = p[i];// c由于精度问题,可能会偏小,所以有些点本应在右侧而没在,  
        //故应该接着判断  
        else {  
            if(a*p[i-1].x + b*p[i-1].y + c > 0){//如果p[i-1]在直线的右侧的话,  
                //则将p[i],p[i-1]形成的直线与已知直线的交点作为核的一个顶点(这样的话,由于精度的问题,核的面积可能会有所减少)  
                q[++curCnt] = intersect(p[i],p[i-1],a,b,c);  
            }  
            if(a*p[i+1].x + b*p[i+1].y + c > 0){//原理同上  
                q[++curCnt] = intersect(p[i],p[i+1],a,b,c);  
            }  
        }  
    }  
    for(int i = 1; i <= curCnt; ++i)p[i] = q[i];//将q中暂存的核的顶点转移到p中  
    p[curCnt+1] = q[1];p[0] = p[curCnt];  
    cCnt = curCnt;  
}  
int solve(){  
  //注意:默认点是顺时针,如果题目不是顺时针,规整化方向  
    initial();  
  /*for(int i = 1; i <= m; ++i){  
        double a,b,c;  
        getline(points[i],points[i+1],a,b,c);  
        cut(a,b,c);  
    }  */

    //如果要向内推进r,用该部分代替上个函数 
    for(int i = 1; i <= m; ++i){ 
        point ta, tb, tt; 
        tt.x = points[i+1].y - points[i].y; 
        tt.y = points[i].x - points[i+1].x; 
        double k = r / sqrt(tt.x * tt.x + tt.y * tt.y); 
        tt.x = tt.x * k; 
        tt.y = tt.y * k; 
        ta.x = points[i].x + tt.x; 
        ta.y = points[i].y + tt.y; 
        tb.x = points[i+1].x + tt.x; 
        tb.y = points[i+1].y + tt.y; 
        double a,b,c; 
        getline(ta,tb,a,b,c); 
        cut(a,b,c); 
    }
 /*   //多边形核的面积 
    double area = 0; 
    for(int i = 1; i <= curCnt; ++i) 
        area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y; 
    area = fabs(area / 2.0); 
 */  if(cCnt<=0)return 0;  
    return 1;

}  
void GuiZhengHua(){ 
     //规整化方向,逆时针变顺时针,顺时针变逆时针 
    for(int i = 1; i < (m+1)/2; i ++) 
      swap(points[i], points[m-i]); 
}
int main()  
{
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
        scanf("%lf%lf",&points[i].x,&points[i].y);

    double x1=points[0].x,x2=points[1].x,x3=points[2].x,y1=points[0].y,y2=points[1].y,y3=points[2].y;
    if((x2-x1)*(y3-y2)-(y2-y1)*(x3-x2)>0)
    {
        GuiZhengHua();
    } points[m+1] = points[1]; 
    double high = 2000000;  
    double low = 0,mid;  
    while(low + eps <= high){  
        mid = (high + low)/2.0;  
        r=mid;
        if(solve())low = mid;  
        else high = mid;  
    }  
    printf("%lf\n",high);  
}  

Problem T. The dividing line (Junior)

题意:给你n个点,m条直线,对于每条直线,求是否有两个点在不同侧。

题解:n*m暴力判断点与直线的关系。

代码:

#include<cstdio>
#include<iostream> 
using namespace std;
typedef long long ll;
ll n,m,x1,x2,y1,y2,a,b;
struct node{
    ll x,y;
}e[10005];
ll cal(ll x,ll y){
    return (y2-y1)*(x-x1)-(y-y1)*(x2-x1);
}
int main(){
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)    scanf("%lld%lld",&e[i].x,&e[i].y);
    scanf("%lld",&m);
    while(m--){
        a=0;
        b=0;
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        for(ll j=1;j<=n;j++){
            if(cal(e[j].x,e[j].y)>0&&a==0)  a=j;
            else if(cal(e[j].x,e[j].y)<0&&b==0) b=j;
            if(a!=0&&b!=0){
                printf("%lld %lld\n",min(a,b),max(a,b)); 
                break; 
            }
        }
        if(a==0||b==0)  printf("0\n"); 
    }
    return 0;
} 

Problem V. Stringangulation (Junior)

题意:给你一个环形的串,求分割三次后,得到a,b,c三个串。问有多少分割满足a+b>c&&a+c>b&&b+c>a(这里是字符串比较与字符串拼接)

题解:n^4暴力分割比较

代码:

#include<bits/stdc++.h>
using namespace std;
vector<int>p[300];
string st;
string a,b,c;
int ans;
int main(){
    cin>>st;
    for(int i=0;i<st.size();i++)    p[st[i]].push_back(i);
    for(int i=0;i<256;i++){
        if(p[i].size()>=3){
            for(int j=0;j<p[i].size();j++){
                for(int k=j+1;k<p[i].size();k++){
                    for(int kk=k+1;kk<p[i].size();kk++){
                        a.clear();
                        b.clear();
                        c.clear();
                        for(int ss=p[i][j];ss!=p[i][k];ss=(ss+1)%st.size())   a+=st[ss];
                        for(int ss=p[i][k];ss!=p[i][kk];ss=(ss+1)%st.size())   b+=st[ss];
                        for(int ss=p[i][kk];ss!=p[i][j];ss=(ss+1)%st.size())   c+=st[ss];
                        if(a+b>c&&b+c>a&&c+a>b) ans++;
                    }
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值