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

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章