回 帖 发 新 帖 刷新版面

主题:第63次编程比赛

大家都快放假了,春节也临近,所以弄两道比较简单的题目,希望大家喜欢。
[em11][em11]

1.Stan是个懒惰的孩子,他做任何事总希望能找到既省力又快捷的方法。Stan的父母开着一家餐馆。餐馆有n*n张桌子,排放成n*n的方阵,每个桌子都有一个坐标,左上角的桌子的坐标为(1,1),其右面的桌子坐标为(1,2),其下面的桌子的坐标为(2,1).....最右下角桌子的坐标为(n,n)。Stan每天都要帮助他父母擦桌子,他当然不打算自己一个人干,所以他召唤出了一只小精灵。
   小精灵只有一项技能:当Stan擦了坐标为(x,y)的桌子时,小精灵会自动帮他把所有坐标为(kx,ky)(k=2,3,.........,,使得kx<=n,且ky<=n)的这些桌子擦干净。现在,Stan想知道对于n*n张桌子,他最少需要擦多少张桌子就能把桌子全部擦干净。
   比如n=4时,Stan只要擦(1,1), (1,2), (1,3), (1,4), (2,1), (2,3), (3,1), (3,2), (3,4), (4,1), (4,3)这些桌子。
   
输入:
    首先第一行,输入一个测试数量t,接下来t行,每行一个n。
输出: 
    t行,每行对应一个解,就是Stan最少要擦几张桌子。
样例:
输入:
3
1
2
3
输出:
1
3
7
为保证正确性,你可以按照如下格式编程
   int main()
   {
       int case;
       scanf("%d",&case);
       while(case--){
       //你的代码
       }
       return 0; 
   }

有两组测试数据:(1)0 <n <=1000,时间:5秒.内存:32MB
               (2)0 <n <=1,000,000 时间:2秒.内存:32MB

2.世界上有鬼吗?如果有,那就一定有捉鬼大师。但捉鬼大师们法力有限,他们只能消灭位于他们东南面的鬼。也就是说,如果把捉鬼大师所在位置视为原点,那么他们只能消灭第四象限的鬼怪(位于x正半轴和y负半轴上的鬼也会被消灭)。
   现在给出一些鬼和坐标和一些捉鬼大师的坐标,请问有多少个鬼不会被消灭?
输入:
   第一行,给出两个数字g,b对应予鬼的个数和捉鬼大师的个数。接下来的g行,每行两个整数,是每个鬼的坐标(之间有一个空各分开),在接下来得b行,每行两个整数,是每个捉鬼大师的坐标(之间有一个空各分开),不会有重复的鬼或重复的捉鬼大师出现。
输出: 
   无法被消灭的鬼的坐标x,y,之间用一个空格分开。注意这些坐标输出顺序必须 按照y值得绛序排列,当y相等时,则按照x的绛序排列。
样例:
输入:
3 2
0 5
1 2
2 3
1 4
-2 3
输出:
0 5
建议:
 int main()
   {
       int g,b;
       scanf("%d %d",&g,&b);
       for(int i=0;i<g;i++)
         //读入鬼坐标
       for(int i=0;i<b;i++)
         //读入捉鬼大师坐标     
       //你的代码
       return 0; 
   }

有两组测试数据:(1)0 <g,b<=8000,时间:2秒,内存:32MB
               (2)0 <g,b<=150000,时间:2秒,内存:32MB


环境:p4 2.2  512M  gcc or g++   64位数据请使用long long int


如有问题请在这里提问
[url=http://www.programfan.com/club/post-266202.html ]http://www.programfan.com/club/post-266202.html [/url]

回复列表 (共13个回复)

沙发

隐藏了

板凳

[size=4]雖然達不到要求,還是跟帖,重在參與~
不過我對題目有異議 據我所知 目前的餐館最多放300張桌子。 像這樣一百萬的平方數量級的桌子,哪有地方放得下?
[/size]
[code]
/* 第一題 */

#include<stdio.h>
int main()
{
    long n,i,j,a,b,tmp;
    long long s;
    int casa;
    scanf("%d",&casa);
    while(casa--)
    {
        scanf("%ld",&n);
        s=n;
        for(i=2;i<=n;i++)
            for(j=2;j<i;j++)
            {
                a=i;b=j;
                while(tmp=a%b)
                {
                    a=b;
                    b=tmp;
                }
                if(b==1) s++;
            }
        s=2*s-1;
        printf("%lld\n",s);
    }
return 0; 
}

[/code]

[code]
/* 第二題 */
#include<stdio.h>
#include<stdlib.h>
int main()
{
    long g,b,i,j,tmp;
    long *cg, *cb, *pg;
    scanf("%ld %ld",&g,&b);
    cg=(long *)malloc(2*g*sizeof(long));
    cb=(long *)malloc(2*b*sizeof(long));
    pg=(long *)malloc(g*sizeof(long));
    for(i=0;i<g;i++)
    {
        pg[i]=i;
        scanf("%ld %ld",&cg[2*i],&cg[2*i+1]);
    }
    for(i=0;i<b;i++)
    {
        scanf("%ld %ld",&cb[2*i],&cb[2*i+1]);
    }
    for(i=0;i<b;i++)
    {
        for(j=0;j<g;j++)
        {
            if(cg[pg[j]*2]<cb[2*i] || cg[2*pg[j]+1]>cb[2*i+1])
                continue;
            pg[j]=pg[--g];
        }
        if(!g) break;
    }
    for(i=0;i<g-1;i++)
        for(j=i+1;j<g;j++)
            if(cg[2*pg[i]+1]<cg[2*pg[j]+1])
            {
                tmp=pg[i];
                pg[i]=pg[j];
                pg[j]=tmp;
            }
    for(i=0;i<g;i++)
        printf("%ld %ld\n",cg[pg[i]*2],cg[2*pg[i]+1]);
    free(cg);
    free(cb);
    free(pg);
    return 0;
}

[/code]

3 楼

/*
  程序名:擦桌子

  程序思路:

  1。建立二维数组;
  2。从(1,1)开始穷举,直到所有的位置都穷尽。
  
  作者:麦子
*/

#include "stdio.h"
#define N 1000000



   main()
   {

       unsigned int  i,j,k,t1,t2;
       unsigned int  m;
       unsigned int  n1,n2,n;
       unsigned int a[N][N]={0,0};

       scanf("%d",&m);

       while(m--)
      {
       printf("\n");
       scanf("%d",&n);

       n1=n2=0;
       for(i=0;i<n;i++)
       for(j=0;j<n;j++)
    a[i][j]=0;


       for(i=0;i<n;i++)
       {

     for(j=0;j<n;j++)
         {
           if(a[i][j]==0)
           {
             t1=i;
             t2=j;

         for(k=1;((t1+1)*k<=n)&&((t2+1)*k<=n);k++)
             {
           a[k*(t1+1)-1][k*(t2+1)-1]=1;
           n1++;

             }
              n2++;
           }
         if(n1==n*n)
          {
       printf("%d",n2);
           break;
          }

     }
          if(n1==n*n)
            break;

        }


    }
     printf("\n");
     getchar();
     getchar();
   }



 /*
  程序名:捉鬼

  程序思路:
  1。先输入鬼和捉鬼大师,并且用两个数组纪录;
  2。按捉鬼大师的坐标逐个杀鬼,直到所有的鬼都被捉到,捉到的置0;
  3。将没捉到的抓出来?
  4. 当出现(0,0)作为鬼时分开讨论。

  作者:麦子
*/

#include "stdio.h"
#define N 150000


 int main()
   {
      int g,b;
      int a[N][2]={0},c[N][2]={0};
      int i,j;
      int temp,n=0;
      int flag=0;

       scanf("%d %d",&g,&b);
       printf("\n");

       for(i=0;i<g;i++)
    {
      getchar();
      scanf("%d %d",&a[i][0],&a[i][1]);

    }
       for(i=0;i<b;i++)
    {
     getchar();
          scanf("%d %d",&c[i][0],&c[i][1]);

        }

        for(i=0;i<g;i++)
        {
         if((a[i][0]==0)&&(a[i][1]==0))
         {
           for(j=0;j<b;j++)
           {
            if((a[i][0]<c[j][0])||(a[i][1]>c[j][1]))
            {
             flag=1;
            }

         }



4 楼

第一题:
/*****************************************************************************
原始思路:求最大公约数。
坐标为(x, y)的桌子,求x和y的最大公约数,若为1则需要擦,否则不需要擦。证明略。
时间复杂度:O(n^2 * 求最大公约数的复杂度),百万的数量级无法快速算出。

另外途径:
共n*n张桌子,本来需要擦n*n次
[以下均假设k为正证书,且坐标都小于等于n]
先考虑(k, k)的情况,可少擦k-1次
再考虑(k, 2k), (k, 3k), ..., (k, nk)
  以及(2k, k), (3k, k), ..., (nk, k)
对于(k, ik),可少擦n/i+1次
对于(ik, k),可少擦n/i+1次

注意使用long long int来避免数据溢出
 *****************************************************************************/

/*****************************************************************************
编程语言:C语言
测试环境:Visual Studio 2005
 *****************************************************************************/

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

long long int cal(int n) {
    int i;
    long long int ret = ((long long int)n) * n;
    ret += (1 - n);
    for(i=2; i<=n; ++i) {
        int count = n / i;
        ret += (1-count)*2;
    }
    return ret;
}

int main() {
    int nCase;
    scanf("%d", &nCase);
    while( nCase-- ) {
        int n;
        scanf("%d", &n);
        printf("%I64ld\n", cal(n));
    }
    return 0;
}

5 楼

第二题:
/*****************************************************************************
原始思路:
考虑到对输出结果顺序的要求,先排序后判断
注意数量级在15万时,直接比较是不可行的,因为直接比较的时间复杂度是平方级

优化:
  多处利用空间换取时间。记录鬼的位置要记录三份:
一份是输出要求的顺序,一份是x坐标顺序,一份是y坐标顺序。
其中第一份是实际的数据,后两份都是指针,
这样保证所有的数据最终都指向同一个地方。便于做标记。
  对于给定的捉鬼大师,先找Y坐标相同的鬼。这样可以排除Y坐标大的鬼,做标记。
O(log(n) + 做标记的时间)
再找X坐标相同的鬼,这样可以排除X坐标小的鬼。O(log(n) + 做标记的时间)
未排除的鬼会被捉。
  时间复杂度:O(n*log(g)+做标记的时间),
做标记时需要较多时间,O(n*(log(g)+g*c)) = O(n*log(g) + n*g*c),而其中c较小。

再次优化:
  并非每个捉鬼大师都需要与每个鬼进行判断。所有的大师中,只有最左上方的才是有效的。
比如有三个大师(0, 0), (0, -1), (-1, 0),则其实大师(0, 0)即使不存在,也没有任何影响。
所有有效的大师组成一个阶梯状。先把大师按x坐标排序,x坐标相等的按y坐标排序。
y坐标比前一个大师大的大师才是有效的。
  优化后虽然最坏情况下复杂度不变,但是对随机数据可大幅度提高性能。

小技巧:
使用C++的sort排序,可达到比C语言的qsort更快的速度

不足:
使用了set,这个地方应该还有优化余地
 *****************************************************************************/

/*****************************************************************************
编程语言:C++
测试环境:Visual Studio 2005
 *****************************************************************************/

#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <set>
#include <algorithm>

using namespace std;

struct Ghost {
    int x;
    int y;
    int catched;

    Ghost() : catched(0) {
    }

    Ghost(int x, int y) : x(x), y(y), catched(0) {
    }
};

struct Catcher {
    int x;
    int y;
};

static bool comp_catcher_xy_less(const Catcher& a, const Catcher& b) {
    if( a.x < b.x )
        return true;
    if( a.x == b.x && a.y < b.y )
        return true;
    return false;
}

static bool comp_ghost_yx_greater(const Ghost& a, const Ghost& b) {
    if( a.y > b.y )
        return true;
    if( a.y == b.y && a.x > b.x )
        return true;
    return false;
}

static bool comp_ghost_x_less(Ghost* const& a, Ghost* const& b) {
    return a->x < b->x;
}

static bool comp_ghost_y_less(Ghost* const& a, Ghost* const& b) {
    return a->y < b->y;
}

static int optimizeCatcherList(Catcher* pCatcherList, int nCatcher) {
    sort(pCatcherList, pCatcherList+nCatcher, comp_catcher_xy_less);
    int p = 1;
    for(int i=1; i<nCatcher; ++i) {
        if( pCatcherList[i].y > pCatcherList[i-1].y )
            pCatcherList[p++] = pCatcherList[i];
    }
    return p;
}

int main() {
    int nGhost, nCatcher;
    scanf("%d%d", &nGhost, &nCatcher);
    Ghost* pGhostList = new Ghost[nGhost];
    Catcher* pCatcherList = new Catcher[nCatcher];
    for(int i=0; i<nGhost; ++i)
        scanf("%d%d", &(pGhostList[i].x), &(pGhostList[i].y));
    for(int i=0; i<nCatcher; ++i)
        scanf("%d%d", &(pCatcherList[i].x), &(pCatcherList[i].y));

    // 排除无影响的大师
    nCatcher = optimizeCatcherList(pCatcherList, nCatcher);

    // 将鬼按输出要求排序
    sort(pGhostList, pGhostList+nGhost, comp_ghost_yx_greater);

    // 复制鬼数据指针,按x和y分别排序
    Ghost** pGhostPtrListX = new Ghost*[nGhost];
    Ghost** pGhostPtrListY = new Ghost*[nGhost];
    for(int i=0; i<nGhost; ++i) {
        pGhostPtrListX[i] = &(pGhostList[i]);
        pGhostPtrListY[i] = &(pGhostList[i]);
    }
    sort(pGhostPtrListX, pGhostPtrListX+nGhost, comp_ghost_x_less);
    sort(pGhostPtrListY, pGhostPtrListY+nGhost, comp_ghost_y_less);

    // 实际处理
    for(int i=0; i<nCatcher; ++i) {
        Ghost dummyGhost = Ghost(pCatcherList[i].x, pCatcherList[i].y);
        set<Ghost*> ghostSet;
        // 找出所有x值比大师更大的(含相等),放入集合
        int iX = lower_bound(pGhostPtrListX, pGhostPtrListX+nGhost,
            &dummyGhost, comp_ghost_x_less) - pGhostPtrListX;
        for(i=iX; i<nGhost; ++i)
            if( !pGhostPtrListX[i]->catched )
                ghostSet.insert(pGhostPtrListX[i]);
        // 找出所有y值比大师更小的(含相等),若在集合中有对应元素,则标记为捉住
        int iY = lower_bound(pGhostPtrListY, pGhostPtrListY+nGhost,
            &dummyGhost, comp_ghost_y_less) - pGhostPtrListY;
        for(i=0; i<=iY; ++i)
            if( !pGhostPtrListY[i]->catched )
                if( ghostSet.find(pGhostPtrListY[i]) != ghostSet.end() )
                    pGhostPtrListY[i]->catched = 1;
    }

    // 输出
    for(int i=0; i<nGhost; ++i)
        if( !pGhostList[i].catched )
            printf("%d %d\n", pGhostList[i].x, pGhostList[i].y);

    delete[] pGhostList;
    delete[] pGhostPtrListX;
    delete[] pGhostPtrListY;
    delete[] pCatcherList;
    return 0;
}

6 楼

#include "stdio.h"

int CD(int x)//第x行第x列,不需要擦的个数
{    
    int n,m,k=0;
    for(n=2; n<x; n++)
    {
        for(m=2;m<=n;m++)
        {
            if(n%m==0 && x%m==0)    
            {    
                k++;
                break;
            }
        }
    }
    k=2*k+1;
    return k;
}




int main()
{
    int t;
    int n,m,k;
    scanf("%d",&t);

    while(t--)
    {
        m=0;
        k=0;
        scanf("%d",&n);
        if(n==1)
            m=1;
        else
        {
            for(int i=2;i<=n;i++)
            {
                k+=CD(i);
            }
            m=n*n-k;
        }

        printf("%d\n",m);
    }

    return 0; 
}

7 楼

1.
#include <conio.h>        /* 此头函数请不要删除 */
#include<stdio.h>
main()
{int n,i,j,k,s;
s=0;
scanf("%d",&n);
for(i=2;i<=n;i++)
{for(j=2;j<=n;j++)
{for(k=2;k<=n;k++)
{if(i/k>0&&i/k<n&&i%k==0&&j/k>0&&j/k<n&&j%k==0)
{s++;
break;}}}}
s=n*n-s;
printf("%d",s);
 getch();        /* 此语句请不要删除*/
}

2.#include <conio.h>        /* 此头函数请不要删除 */
#include<stdio.h>
main()
{int g,b,i,j,m,n,x1[10],x2[10],y1[10],y2[10];
m=0;
n=0;
scanf("%d &d",&g,&b);
for(i=0;i<g;i++)
scanf("%d &d",&x1[i],&y1[i]);
for(j=0;j<b;j++)
scanf("%d &d",&x2[j],&y2[j]);
for(j=0;j<b;j++)
for(i=0;i<g;i++)
{if(x2[j]>x1[i]&&y2[j]<y1[i])
{if(m!=x1[i]&&n!=y1[i])
{m=x1[i];
n=y1[i];
printf("%d %d",m,n);}}}
 getch();        /* 此语句请不要删除*/
}

8 楼

[code=c]
//小孩擦桌子
#include <iostream>
using namespace std;

const int MAX = 2000000;
void track(int);

int main() {
    int ipn = 0;    
    cout << "put the test number: ";
    cin >> ipn;
    if( ipn > MAX  )
    {
        cout << "Too large number!" << endl;
        return -1;
    }
    else cout << "no.   " <<"test number" << endl;
    track(ipn);
    return 0;
}

void track(int ipn) {
    long long int count = 0;
    for (int i = 0; i < ipn; ++i) {
        if ( (i & 0x00000001 ) == 1)
            count += i - ( (i - 1 ) >> 1 );
        else
            count += i;
        cout << i + 1 << "      " << count + count + 1 << endl;
    }
}
[/code]

9 楼

[code=c]
//鬼大师捉鬼
#include <iostream>
using namespace std;

typedef struct LocalType {
    int x;
    int y;
}LocalType;

int  partition( LocalType*, int, int, char );
void quickSort( LocalType*, int, int, char );
int  sort( LocalType*, int ); //先y升序,再x升序

int main() {
    int g, b, count_g, count_b, count = 0;
    cout << "输入:" << endl;
    cin >> g;
    cin >> b;
    
    LocalType *local_g = new LocalType[g];
    LocalType *local_b = new LocalType[b];
    
    int i = 0;
    for ( i = 0; i < g; ++i ) {
        cin >> local_g[i].x;
        cin >> local_g[i].y;
    }
    for ( i = 0; i < b; ++i ) {
        cin >> local_b[i].x;
        cin >> local_b[i].y;
    }
    
    count_g = sort ( local_g, g );
    count_b = sort ( local_b, b );
    LocalType *local_t = new LocalType[count_b];

    for ( i = b - 1; i >= 0; --i ) { //筛选有用的道士
        while ( i > 0 && local_b[i].y == local_b[ i - 1 ].y )  --i;
        if ( count == 0 || local_b[i].x < local_t[ count -1 ].x ) {
            local_t[count] = local_b[i];
            ++count;
        }//if
    }//for

    delete [] local_b;
    cout << "输出:" << endl;

    int j = 0;
    for ( i = g - 1; i >= 0; --i ) { //输出鬼,y降序,再x降序
        while ( j < count && local_g[i].y <= local_t[j].y )  ++j;
        if ( local_g[i].y > local_t[0].y || local_g[i].x < local_t[ j - 1 ].x ) {
            cout << local_g[i].x << " " << local_g[i].y << endl;
            j = 0;
        }//if
    }//for
    
    delete [] local_g;
    delete [] local_t;    
    return 0;
}

int partition( LocalType *L, int low, int high, char a ) {    
    int pivot = 0;
    LocalType t = L[low];
    if ( a == 'x' ) {        
        pivot = L[low].x;    
        while ( low < high ) {
            while ( low < high && L[high].x >= pivot ) --high;
            L[low] = L[high];
            while ( low < high && L[low].x <= pivot ) ++low;
            L[high] = L[low];
        }
    }
    else {
        pivot = L[low].y;
        while ( low < high ) {
            while ( low < high && L[high].y >= pivot ) --high;
            L[low] = L[high];
            while ( low < high && L[low].y <= pivot ) ++low;
            L[high] = L[low];
        }
    }
    L[low] = t;
    return low;
}//partition

void quickSort( LocalType *L, int low, int high, char a ) {
    int pivot = 0;
    if ( low < high ) { 
        pivot = partition( L, low, high, a );
        quickSort( L, low, pivot - 1, a );
        quickSort( L, pivot + 1, high, a );
    }
}//quickSort

int sort( LocalType *L, int size ) {
    int count = 0;
    int low, high;
    quickSort( L, 0, size - 1, 'y' );
    for ( int i = 0; i < size; ++i ) {
        low = i;
        while ( i + 1 < size && L[i].y == L[ i + 1 ].y )  ++i;
        high = i;
        quickSort ( L, low, high, 'x' );
        count++;
    }
    return count;
}
[/code]

10 楼


#include <iostream>
using namespace std;

class CNum{
private:
    int n;
    int Factors;
    int Factor[7];//[0]为素因子个数,其后为素因子列表
public:
    int Euler();
    int GetN(){return n;}
    bool IsPrime(){return Factors == 0;}
    void AddPrime(int p){    Factors ++;    Factor[Factors-1] = p;}
    void Set(int nn){    n = nn;    Factors = 0;}
    CNum(int nn){    Set(nn);}
    CNum(){}
};

int CNum::Euler()
{
    int tmp = 1;
    int temp = 1;
    for(int i=0;i<Factors;i++){
        tmp *= Factor[i];
        temp *= Factor[i] - 1;
    }
    return n/tmp*temp;
}

class CNode{
private:
    int num;
    int tmp;
    CNode *N;
public:
    CNode(){    Set(0,0,NULL);}
    CNode(int n,int t){    Set(n,t,NULL);}
    void Set(int n,int t,CNode *p){    num = n;tmp = t;    N = p;}
    void SetTmp(int t){    tmp = t;}
    int GetTmp(){return tmp;}
    void SetNext(CNode *p){    N = p;}
    CNode* GetNext(){return N;}
    int GetNum(){return num;}
    void MoveTmp(int t){tmp -= t;}
    ~CNode(){    if (N)         delete N;}
};


//返回i,j (i<=n,j<=n) 互质的对数 即本题结果
long long tables(int n)
{
    long long result = 1;    //结果
    long long tmp = 0;        //2..n的欧拉函数总和
    int start = 2;            //第一个数
    const int LEN = 25000;        //数组长
    CNum cn[LEN];            //数组
    int cnl = 0;            //数组有效长度
    CNode *Head = new CNode;    //素数链表
    CNode *Tail = Head;
    while(start<=n){
        //确定长度
        cnl = (LEN < (n-start+1)) ? LEN : (n-start+1);
        //初始化数组
        for(int i=0;i<cnl;i++){
            cn[i].Set(start + i);
        }
        //用素数列表中的数字筛选数组
        CNode *p = Head;
        while(p = p->GetNext()){
            int i;
            for(i=p->GetTmp();i<cnl;i+=p->GetNum()){
                cn[i].AddPrime(p->GetNum());
            }
            p->SetTmp(i);
            Tail = p;
        }
        //将数组中的素数加入素数列表 并筛选数组
        for(int i=0;i<cnl;i++){
            if(cn[i].IsPrime()){
                p = new CNode(cn[i].GetN(),i);
                Tail->SetNext(p);
                Tail = p;
                int j;
                for(j=p->GetTmp();j<cnl;j += p->GetNum()){
                    cn[j].AddPrime(p->GetNum());                
                }
                p->SetTmp(j);
            }
        }
        //计算数组各项的欧拉函数 并 求和
        for(int i=0;i<cnl;i++){
            tmp += cn[i].Euler();
        }
        //对素数链表偏移
        p = Head;
        while(p = p->GetNext()){
            p->MoveTmp(cnl);
        }
        start += cnl;
    }
    
    result += 2*tmp;

    return result;
}

int main()
{
    int lines;
    int n;
    clock_t start,finish;
    double  duration;

    cin>>lines;
    while(lines --){
        cin>>n;
        cout<<tables(n)<<endl;    

    }
    cin>>lines;
    return 0;
}


如果溢出,楼主帮忙修改一下 const int LEN = 25000;        //数组长
LEN越大效率越高,

我来回复

您尚未登录,请登录后再回复。点此登录或注册