2018CCPC桂林站题解(D G H J L)

题目链接:http://codeforces.com/gym/102823

问题 D: Bits Reverse

时间限制: 1 Sec  内存限制: 128 MB
提交: 167  解决: 127
[提交] [状态] [命题人:admin]

题目描述

Now given two integers x and y, you can reverse every consecutive three bits in arbitrary number’s binary form (any leading zero can be taken into account) using one coin. Reversing (1,2,3) means changing it into (3,2,1).
Could you please find a way that minimize number of coins so that x = y? If you can, just output the minimum coins you need to use.

输入

The first line of input file contains only one integer T (1≤T≤10000) indicating number of test cases.
Then there are T lines followed, with each line representing one test case.
For each case, there are two integers x, y (0≤x,y≤10^18) described above.

输出

Please output T lines exactly.
For each line, output Case d: (d represents the order of the test case) first. Then output the answer in the same line. If there is no way for that, print -1 instead.

样例输入

复制样例数据

3
0 3
3 6
6 9

样例输出

Case 1: -1
Case 2: 1
Case 3: 2

提示

Sample 1: Considering following two binary string:
0: 0 ...0000
3: 0 ...0011
There is no way to achieve the goal.
Sample 2: Considering following two binary string:
3: 0 ...0011
6: 0 ...0110
You can reverse the lowest three digits in 3 so that 3 is changed into 6.
You just need to perform one reverse so that the minimum coin you need to use is 1.

【题意】

T组输入,每组输入包含两个数字x和y(long long int)。对x有一种操作,可以将 x的二进制 任意相邻的三个位逆置。

问最少进行多少次操作,可以使得x等于y

【分析】

首先将x和y分别转为二进制并存在数组里。

任意相邻三个位逆置,其实不影响中间那一位,也就是隔位交换。所以奇数位和偶数位分别考虑即可。

对于奇数位,x和y的1的个数若不相等,则无解;否则,设x中1的位置列表ai,y中1的位置列表bi。则ans=\sum [(a_{i}-b_{i})/2]

偶数位同理,ans加在一起即为答案。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1e6+5;

int T;
ll x,y;
int a[300],b[300];
int v[100],u[200];
int main()
{
    int cas=0;
    for(cin>>T;T--;)
    {
        scanf("%lld%lld",&x,&y);
        printf("Case %d: ",++cas);
        int top=62;
        for(int i=0;i<62;i++)
        {
            a[i]=x>>i&1;
            b[i]=y>>i&1;
        }

        //奇数位置
        int ku=0,kv=0;
        for(int i=0;i<62;i+=2)
        {
            if(a[i])u[ku++]=i;
            if(b[i])v[kv++]=i;
        }

        if(ku!=kv)
        {
            puts("-1");
            continue;
        }

        ll ans=0;
        for(int i=0;i<ku;i++)ans+=abs(u[i]-v[i])/2;

        //偶数位置
        ku=0,kv=0;
        for(int i=1;i<62;i+=2)
        {
            if(a[i])u[ku++]=i;
            if(b[i])v[kv++]=i;
        }

        if(ku!=kv)
        {
            puts("-1");
            continue;
        }
        for(int i=0;i<ku;i++)ans+=abs(u[i]-v[i])/2;
        printf("%lld\n",ans);
    }
}

问题 G: Greatest Common Divisor

时间限制: 1 Sec  内存限制: 128 MB
提交: 556  解决: 66
[提交] [状态] [命题人:admin]

题目描述

There is an array of length n, containing only positive numbers.
Now you can add all numbers by 1 many times. Please find out the minimum times you need to perform to obtain an array whose greatest common divisor(gcd) is larger than 1 or state that it is impossible.
You should notice that if you want to add one number by 1, you need to add all numbers by 1 at the same time.

输入

The first line of input file contains an integer T (1≤T≤20), describing the number of test cases.
Then there are 2×T lines, with every two lines representing a test case.
The first line of each case contains a single integer n (1≤n≤105) described above.
The second line of that contains n integers ranging in [1,109].

输出

You should output exactly T lines.
For each test case, print Case d: (d represents the order of the test case) first. Then output exactly one integer representing the answer. If it is impossible, print -1 instead.

样例输入

复制样例数据

3
1
2
5
2 5 9 5 7
5
3 5 7 9 11

样例输出

Case 1: 0
Case 2: -1
Case 3: 1

提示

Sample 1: You do not need to do anything because its gcd is already larger than 1.
Sample 2: It is impossible to obtain that array.
Sample 3: You just need to add all number by 1 so that gcd of this array is 2.

注,该题题解由队友提供。

【题意】

你n个数,每次给所有的数+1,问最少加多少次使得所有的数的gcd>1.
【分析】:

如果最后的gcd>1,那么n个数每个数都是gcd的倍数,那么他们的差值也是gcd的倍数,所以求所有差值(排序后)的gcd,如果gcd==1,则没有办法使他们的gcd>1,但是需要特判下如果所有的数都相等而且>=2,那么0次就够了,如果==1的话则需要都加1.对于其他情况的话,暴力求出来gcd的因子,然后对于随便一个数验证次数,取一个最小值即可。

【代码】

/*
Look at the star
Look at the shine for U
*/
#include<bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define sl(x) scanf("%lld",&x)
using namespace std;
const int N = 1e6+5;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
ll s[N],fac[N],cnt;
int main()
{
    ll n,i,j,k,sum,t,cas = 1;
    sl(t);
    while(t--)
    {
        sl(n);
        sum = 0;
        for(i = 0;i < n;i++){sl(s[i]),sum += s[i];}
        printf("Case %lld: ",cas++);
        if(sum == n)
        {
            puts("1");
            continue;
        }
        sort(s,s+n);
        ll flag = 0;
        for(i = 0;i < n;i++)
        {
            if(s[i]%s[0]) flag = 1;
        }
        if(!flag && s[0] != 1)
        {
            puts("0");
            continue;
        }
        ll Gcd = 0;
        for(i = 1;i < n;i++)
        {
            ll dis = s[i]-s[i-1];
            if(dis == 0) continue;
            Gcd = __gcd(Gcd,dis);
        }
        if(Gcd == 1)
        {
            puts("-1");
            continue;
        }
        flag = 0;
        for(i = 0;i < n;i++)
        {
            if(s[i]%Gcd) flag = 1;
        }
 
        if(!flag)
        {
            puts("0");
            continue;
        }
        cnt = 0;
        for(i = 2;i*i <= Gcd;i++)
        {
            if(Gcd%i == 0)
            {
                fac[cnt++] = i;
                fac[cnt++] = Gcd/i;
            }
        }
        fac[cnt++] = Gcd;
        sort(fac,fac+cnt);
        ll minn = 1e18;
        ll now = 0;
        for(i = 0;i < cnt;i++)
        {
            ll temp = 0;
            for(j = 0;j < n;j++)
            {
                if(s[j]%fac[i]) temp = 1; 
            }
            if(!temp)
            {
                now = 1;
                break;
            }
        }
        if(now)
        {
            puts("0");
            continue;
        }
        for(i = 0;i < cnt;i++)
        {
            minn = min(minn,fac[i]-s[0]%fac[i]);
        }
        printf("%lld\n",minn);
    }
}

问题 H: Hamming Distance

时间限制: 1 Sec  内存限制: 128 MB
提交: 169  解决: 23
[提交] [状态] [命题人:admin]

题目描述

In information theory, the Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. In other words, it measures the minimum number of substitutions required to change one string into the other, or the minimum number of errors that could have transformed one string into the other.– Wikipedia
Assume that there are two strings with same length, which only contain lowercase characters, find a lexicographically smallest string with same length, and the Hamming distance between the target string and each original string are equal.

输入

The first line contains a number T (1≤T≤100), indicating the number of test cases.
Each time case contains two lines of strings, indicating the two original strings, which only contain lowercase characters. The length of string is smaller than 10^4, and total length of the strings is less then 10^6.

输出

For each case, output "Case x: y in which x indicates the case number starting with 1, and y indicates the result of the target string. The target string should only contain lowercase characters.

样例输入

复制样例数据

2
abc
acd
abandon
newyork

样例输出

Case 1: aaa
Case 2: aaaaark

【题意】

汉明码?字符串a和字符串b长度相等,其汉明码距离为  有多少个i满足a[i]!=b[i]

每组输入是长度相等的两个字符串s和t,请你求出一个字符串str,满足 str和s的汉明码距离 等于 str和t的汉明码距离。

存在多组解,则输出字典序最小的一个。

【分析】

假设F(x,y)表示字符串x和y 对应位置相等的 个数,例如F(“abc”,“abb”)= 2

不难发现,s[i]==t[i]时,放什么都不影响汉明码距离的比较,故直接放 'a'

显然,若s和t中都不含'a'时,直接输出"aa...a"即可;当各自含有'a'时,才需要讨论,不妨把含'a'多的串 调整为s,另一个为t。

①首先我们构造一个全'a'的字符串str,此时记下 add=F(str,s)-F(str,t),我们的目标就是把 add 搞成 0

②为了字典序最小,我们希望str靠前的‘a’尽量不变,因此从串尾开始考虑。

整理得,位置 i 能够对add造成影响的情况:

可以看出,当字符a 修改为 b, c, x1, x3 时,可使得add降低

③分情况讨论这5种修改方式即可。需要注意,'a'对应'x1'时,应当优先考虑'b',这时,假设放b,后面还够不够能力把add降为0,即maxChange的作用。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1e6+5;
int T;
char s[MAX],t[MAX],str[MAX];

int main()
{
    int cas=0;
    for(cin>>T;T--;)
    {
        scanf("%s%s",s+1,t+1);
        printf("Case %d: ",++cas);
        int len=strlen(s+1);

        int add=0;
        for(int i=1;i<=len;i++)
        {
            if('a'==s[i])add++;
            if('a'==t[i])add--;
        }

        if(add<0)
        {
            for(int i=1;i<=len;i++)swap(s[i],t[i]);
            add=-add;
        }

        memset(str,'a',sizeof(str[0])*(len+1));
        str[len+1]=0;
        if(add==0)  //全'a'即可
        {
            puts(str+1);
            continue;
        }


        int i,sub=add,maxChange=0; //maxChange记录i后面所能做的最大修改
        for(i=len;i>=1;i--)
        {
            if(s[i]==t[i])continue;

            if(s[i]=='a')maxChange+=2;
            else if(t[i]!='a')maxChange++;

            if(s[i]=='a')
            {
                if(sub>=2)sub-=2;
                else sub--;
            }
            else if(t[i]!='a')sub--;
            if(sub==0)break;
        }


        for(;i<=len;i++) //回去
        {
            if(s[i]==t[i])continue;

            if(s[i]=='a')maxChange-=2;
            else if(t[i]!='a')maxChange--;

            if(s[i]=='a')
            {
                if(t[i]=='b')
                {
                    if(add>=2)
                    {
                        str[i]='b';
                        add-=2;
                    }
                    else if(add>0)
                    {
                        str[i]='c';
                        add--;
                    }
                }
                else //cdef...
                {
                    //放b会使字典序最小,但放b会导致后面就算尽最大努力也平衡不回来了
                    if(add-1>maxChange)
                    {
                        str[i]=t[i];
                        add-=2;
                    }
                    else if(add>0)
                    {
                        str[i]='b';
                        add--;
                    }
                }
            }
            else if(t[i]!='a' && add>0)
            {
                str[i]=t[i];
                add--;
            }
        }

        puts(str+1);
    }
}

问题 J: Stone Game

时间限制: 1 Sec  内存限制: 128 MB
提交: 342  解决: 70
[提交] [状态] [命题人:admin]

题目描述

Alice and Bob are always playing game! The game today is about taking out stone from the stone piles in turn.
There are n piles of stones, and the i-th pile contains A[i] stones.
As the number of stones in each pile differs from its neighbor’s, they determine to take out exactly one stone from one of them in one turn without breaking that property. Alice goes first.
The player who cannot take stone will lose the game.
Now you have to determine the winner given n numbers representing the piles, if they both play optimally.
You should notice that even a pile of 0 stone is still regarded as a pile!

输入

The first line of input file contains an integer T (1≤T≤100), describing the number of test cases.
Then there are 2×T lines, with every two lines representing a test case.
The first line of each test case contains only one integer n (1≤n≤105) as described above.
The second line of that contains exactly n numbers, representing the number of stone(s) in a pile in order.
All these numbers are ranging in [0,109].
It is guaranteed that the sum of n in all cases does not exceed 106.

输出

You should output exactly T lines.
For each test case, print Case d: (d represents the order of the test case) first, then print the name of winner, Alice or Bob .

样例输入

复制样例数据

2
2
1 3
3
1 3 1

样例输出

Case 1: Alice
Case 2: Bob

提示

Sample 1:
There is a possible stone-taking sequence: (1,3)-> (1,2)-> (0,2)-> (0,1)
Here is an invalid sequence: (1,3)-> (1,2)-> (1,1)-> (0,1). Though it has the same result as the first sequence, it breaks that property “the number of stones in each pile differs from its neighbor’s”.

【题意】

n堆石子,保证相邻两堆不等。A和B玩游戏,轮流从这n堆中,任意拿走一颗石子,但需要保证拿走第i堆的一颗石子后,第i堆的石子不能和他相邻堆相等。谁无法拿石子时,谁就输。问谁能赢?

【分析】

设a[x]与a[y]相邻,若a[x]>a[y],则永远不会出现a[x]<=a[y]的情况。于是整个序列的单调性不会发生变化。

找出所有的极小值点(两端特判),这些点最后一定能拿成0。然后从极小值点往两边爬,爬到封顶,爬的时候让a[i]变成前一个+1即可。也就是保持单调性的前提下,尽量降低序列的值。  令sum = 原序列的和 - 现序列的和,则sum为奇数时A赢,否则B赢

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1e6+5;
 
int T;
int n;
int a[MAX];
 
int st[MAX];
 
int main()
{
    int cas=0;
    for(cin>>T;T--;)
    {
        scanf("%d",&n);
        ll sum=0;
        for(int i=1;i<=n;i++)scanf("%d",a+i),sum+=a[i];
        printf("Case %d: ",++cas);
 
        if(n==1)
        {
            puts(sum%2?"Alice":"Bob");
            continue;
        }
 
        int top=0;
        for(int i=2;i<n;i++)
        {
            if(a[i-1]>a[i] && a[i]<a[i+1])st[top++]=i;
        }
 
   //     cout<<"top = "<<top<<endl;
  //      cout<<"st";for(int i=0;i<top;i++)cout<<" "<<st[i];cout<<endl;
 
 
        a[0]=-1;
        for(int i=1;i<n && a[i]<a[i+1];i++)a[i]=a[i-1]+1;
        a[n+1]=-1;
        for(int i=n;i>1 && a[i]<a[i-1];i--)a[i]=a[i+1]+1;
 
 
        for(int i=0;i<top;i++)
        {
            a[st[i]]=0;
            for(int j=st[i]+1;j<n && a[j]<a[j+1];j++)a[j]=a[j-1]+1;
            for(int j=st[i]-1;j>1 && a[j]<a[j-1];j--)a[j]=a[j+1]+1;
        }
   //     cout<<"a: ";for(int i=1;i<=n;i++)cout<<" "<<a[i];cout<<endl;
        for(int i=1;i<=n;i++)
        {
            if(i==1 && a[1]>a[2])a[1]=a[2]+1;
            else if(i==n && a[n]>a[n-1])a[n]=a[n-1]+1;
            else if(a[i-1]<a[i] && a[i]>a[i+1])
                a[i]=max(a[i-1],a[i+1])+1;
        }
   //     cout<<"a: ";for(int i=1;i<=n;i++)cout<<" "<<a[i];cout<<endl;
 
        for(int i=1;i<=n;i++)sum-=a[i];
        puts(sum%2?"Alice":"Bob");
    }
}
 

问题 L: Two Ants

时间限制: 1 Sec  内存限制: 128 MB  Special Judge
提交: 72  解决: 2
[提交] [状态] [命题人:admin]

题目描述

There are two ants landing on an infinite ground containing two chocolate sticks, one white and one black.
However, they do not know the accurate position of each other.
“Where are you?”, Ant A shouted.
“I don’t know. But from my own view I can see the white stick only!”, Ant B replies.
“Well I cannot get your accurate position but I know where you may be!”, Ant A says.
If two sticks can be regarded as segments which exclude the endpoints and share no more than one common point, can you guess where Ant B may be? Print the total area of that instead.

输入

The first line of input file contains only one integer T (1≤T≤1000) indicating the number of test cases.
Then there are T lines followed, with one test case each line.
For each test case, there are eight integers xw,yw,Xw,Yw,xb,yb,Xb,Yb ranging in [-1000,1000]. The white one is represented by its two endpoints’ positions (xw,yw),(Xw,Yw) and the black one is represented by its two endpoints’ positions (xb,yb),(Xb,Yb).

输出

Print T lines exactly.
For each line, please output Case d: (d represents the order of test case) first and then the answer,whose absolute error should be less than 10-6 . If that area is infinite, print inf as answer instead.

样例输入

复制样例数据

3
0 0 0 1 0 0 1 0
0 0 1 0 0 1 0 -1
1 1 1 2 0 0 0 3

样例输出

Case 1: inf
Case 2: 0.000
Case 3: 0.2500000000

提示

【分析】

几何题。每组输入给出四个点,前两个点是线段W的端点 ,后两个点是线段B的端点。问:你站在线段B上,整个平面你看不到的区域的面积(上图中的s区域)

【分析】

玩了一天。。

为了方便,我对原线段进行了平移+旋转,使得B与y轴重合 且 一端在原点上,记得W是与B同步平移+旋转的,保证相对位置不变。

情况比较多,代码中每一种情况都加了注释。 代码的最后加了一些我出过错的数据

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=1e6+5;
const double eps=1e-8;
struct point{
    double x,y;
    point(double a=0,double b=0):x(a),y(b){}
    void input(){scanf("%lf%lf",&x,&y);}
    void output(){printf("point: %.3f %.3f\n",x,y);}
    friend point operator-(const point &a,const point &b)
    {
        return point(a.x-b.x, a.y-b.y);
    }
    friend point operator*(const point &a,const double k)
    {
        return point(a.x*k, a.y*k);
    }
    friend point operator/(const point &a,const double k)
    {
        return point(a.x/k, a.y/k);
    }
    friend bool operator==(const point &a,const point &b)
    {
        return fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps;
    }

    double norm()const
    {
        return sqrt(x*x+y*y);
    }
};

double det(const point &a,const point &b)
{
    return a.x*b.y - a.y*b.x;
}
double dot(const point &a,const point &b)
{
    return a.x*b.x + a.y*b.y;
}
point rotate_point(const point &p,double A)
{
    return point(p.x*cos(A)-p.y*sin(A), p.x*sin(A)+p.y*cos(A));
}
point interSect(const point &a,const point &b,const point &c,const point &d)
{
    double s1=det(c-a,b-a);
    double s2=det(d-a,b-a);
    return (c*s2-d*s1)/(s2-s1);
}

point B[2],W[2];
void deout()
{
    B[0].output(); B[1].output();     W[0].output(); W[1].output();
    puts("");
}
double solve()
{
    if(B[0].y>B[1].y)swap(B[0],B[1]); //使得B[0]在下

    //平移,使得B[0]为原点
    W[0]=W[0]-B[0];
    W[1]=W[1]-B[0];
    B[1]=B[1]-B[0];
    B[0]=B[0]-B[0];

    //旋转,使得B[1]在y轴上
    double sinxz=det(point(0,1),B[1])/B[1].norm();
    double A = -asin(sinxz); //取负的,转回去
    B[1]=rotate_point(B[1],A);
    W[0]=rotate_point(W[0],A);
    W[1]=rotate_point(W[1],A);

    if(fabs(W[0].x)<eps || fabs(W[1].x)<eps) //w有端点在y轴上
    {
        if(fabs(W[0].x)<eps && fabs(W[1].x)<eps) //两端均在y轴
            return 0;
        point iny = fabs(W[0].x)<eps ? W[0] : W[1];
        if(eps<iny.y && iny.y<B[1].y-eps) //一端在B内
            return 0;
        return -1; //w有一端在y轴上,但不在B内
    }

    //W与B不平行
    if(fabs(W[0].x-W[1].x)>eps)
    {
        point sec = interSect(W[0],W[1], B[0],B[1]);
        if(eps<sec.y && sec.y<B[1].y-eps) return 0; //W或W的延长线穿过B
    }

    //W跨过y轴
    if(W[0].x*W[1].x<-eps)return -2;

    //此处考虑W两端点 和B两端点怎么连
    double sinw0 = det(W[0],W[1])/W[0].norm()/W[1].norm();
    if(W[0].x>eps && sinw0<-eps || W[0].x<-eps && sinw0>eps)swap(W[0],W[1]);

    //有可能W与B对应端点相连,是平行向量
    if(fabs( det(W[0]-B[0],W[1]-B[1]) )<eps)return -3;

    point sec = interSect(B[0],W[0], B[1],W[1]);
    if(sec.x*W[0].x<eps)return -4; //交点和W在y两侧,inf

    double s = det(sec-W[0],sec-W[1])/2;
    return fabs(s);
}
int main()
{
    int cas=0,T;
    for(cin>>T;T--;)
    {
        W[0].input();
        W[1].input();
        B[0].input();
        B[1].input();
        printf("Case %d: ",++cas);
        double ans=solve();
        if(ans<-0.5)puts("inf");
        else printf("%.10f\n",ans);
    }
}
/**
1 -2  0 -1  0 0 0 10
inf

3 2 1 5 6 2 4 78
Case 4: 3.1849315068

9 1 9 6 5 6 9 4
(inf)

1 4 0 5 5 0 6 0
0.00

3 2 4 2 5 3 5 8
0.750000

4 8 6 9 4 1 3 6
5.250000

4 4 8 4 3 3 7 4
inf

2 4 3 4 8 5 6 4
0.000000

1 9 9 1 5 5 1 4
inf

4 3 4 4 4 6 2 9
0.000000

3 3 2 8 2 9 1 2
0
3 3 2 8 2 9 2 1
0.000


1 4 4 3 4 4 8 3
inf  这组特殊inf,最好画画
*/

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值