zoukankan      html  css  js  c++  java
  • 2017-2-24第二周周赛题解

    A题:Morning_X和数独

    题目大意就是

    给你一个数独,让你填数:

    1.每行的九个数字互不相同;

    2.每列的九个数字各不相同;

    3.被分成的3*3的小矩阵中的九个数字互不相同;

    输出完成后的数表,若不能满足上述条件,则输出原图。

    其实就是一个DFS,不断的DFS,失败了就回溯。

    分别用三个数组来标记标记在第i行中是否出现了数字x,标记在第j列中是否出现了数字y,第k个3*3子格中是否出现了数字z

    前两个数组都比较好处理,主要是找出子网格的序号与行i列j的关系

    关系玩过数独的只要稍微推导一下就可以知道关系的数学式为 3*((i-1)/3)+(j-1)/3+1=k

    这样我们就可以记录k个3*3子格中数字z是否出现了:

    AC代码如下:

     1 #include<stdio.h>
     2 #include<string.h>
     3 int a[10][10];
     4 int c[10][10];
     5 int map[10][10];
     6 int s[10][10];
     7 int f(int x,int y)
     8 {
     9     return 3*((x-1)/3)+(y-1)/3+1;
    10 }
    11 void init()
    12 {
    13     int i,j;
    14     char ch;
    15     memset(a,0,sizeof(a));
    16     memset(c,0,sizeof(c));
    17     memset(s,0,sizeof(s));
    18     for(i=1; i<=9; i++)
    19         {
    20             for(j=1; j<=9; j++)
    21             {
    22                 scanf("%c",&ch);
    23                 map[i][j]=ch-'0';
    24                 if(map[i][j])
    25                 {
    26                     int k;
    27                     k=f(i,j);
    28                     a[i][map[i][j]]=1;
    29                     c[j][map[i][j]]=1;
    30                     s[k][map[i][j]]=1;
    31                 }
    32             }
    33             getchar();
    34         }
    35 }
    36 int DFS(int x,int y)
    37 {
    38     if(x==10)
    39         return 1;
    40     int flag=0;
    41     if(map[x][y])
    42     {
    43         if(y==9)
    44             flag=DFS(x+1,1);
    45         else
    46             flag=DFS(x,y+1);
    47         if(flag)
    48             return 1;
    49         else
    50             return 0;
    51     }
    52     else
    53     {
    54         int k=f(x,y);
    55         for(int i=1; i<=9; i++)
    56             if(!a[x][i] && !c[y][i] && !s[k][i])
    57             {
    58                 map[x][y]=i;
    59                 a[x][i]=1;
    60                 c[y][i]=1;
    61                 s[k][i]=1;
    62                 if(y==9)
    63                     flag=DFS(x+1,1);
    64                 else
    65                     flag=DFS(x,y+1);
    66                 if(!flag)
    67                 {
    68                     map[x][y]=0;
    69                     a[x][i]=0;
    70                     c[y][i]=0;
    71                     s[k][i]=0;
    72                 }
    73                 else
    74                     return 1;
    75             }
    76     }
    77     return 0;
    78 }
    79 int main()
    80 {
    81     int t;
    82     scanf("%d",&t);
    83     getchar();
    84     while(t--)
    85     {
    86         init();
    87         DFS(1,1);
    88         for(int i=1; i<=9; i++)
    89         {
    90             for(int j=1; j<=9; j++)
    91                 printf("%d",map[i][j]);
    92             printf("
    ");
    93         }
    94     }
    95     return 0;
    96 }
    View Code

    B题:Morning_X和seventh的字符串

    这是一道水题,

    比较两个字符串是否相等嘛,如果相等就输出-1,否则输出较长的那个字符串长度,可以直接用strcmp进行比较,不过我为了保险就一个一个比较了

    AC代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int main()
     6 {
     7     char a[100005],b[100005];
     8     while(~scanf("%s%s",&a,&b))
     9     {
    10         int len1=strlen(a),len2=strlen(b);
    11         int flag=0;
    12         if(len1!=len2)
    13             flag=1;
    14         for(int i=0;i<len1;i++)
    15             if(a[i]!=b[i])
    16             flag=1;
    17         if(flag==1)
    18             printf("%d
    ",max(len1,len2));
    19         else
    20             printf("-1
    ");
    21     }
    22     return 0;
    23 }
    View Code

    C题:Morning_X的小学数学

    题意就是求n的第K个约数;

    又是一道水题;

    思路其实就是:首先可以求得小于等于根号n的约数,如果k比较小的话直接输出就可以了

    而其他约数均为n/小于根号n的约数,所以数量为2倍。对于根号n为整数的再做个特判就可以了。

    AC代码:

     1 #include<stdio.h>
     2 #include<vector>
     3 using namespace std;
     4 vector <int> x;
     5 int main()
     6 {
     7     long long n;
     8     int k;
     9     scanf("%I64d%d",&n,&k);
    10     for(long long  i=1;i*i<=n;i++)
    11             if(n%i==0)
    12                 x.push_back(i);
    13             if(x.size()>=k)
    14                 printf("%d",x[k-1]);
    15             else
    16             {
    17                 int a=x.size(),s=(long long)x[a-1]*x[a-1]==n;
    18                 if(k>a*2-s)
    19                     printf("-1");
    20                 else
    21                     printf("%I64d",n/(long long)x[2*a-k-s]);
    22             }
    23     return 0;
    24 }
    View Code

    D题:Morning_X的苹果

    这一题的题意其实挺坑的,我题面写的最久的就是这道题;

    题意大概就是

    Morning_X很喜欢吃苹果,每天会吃K个,如果不足K个,就会将所有拥有的都吃了。

    不傻的人都知道,苹果过期了之后肯定就不能吃了,那就只能扔掉。(鬼知道为什么会过期)

    现在冰箱中有N个苹果,超市中有M个苹果,如果冰箱中的苹果吃不完就有浪费的情况出现,输出-1,否则输出能够在超市中购买的苹果数量的最大值。

    并且输出可以购买的苹果的编号。

    这一题还是不要看我的题解比较好,因为我是暴力过的,第一次在OJ上交还超时了,我是卡时间过的233;

    准确的思路是二分加贪心,而我的是二分加暴力处理

    思路:首先我们将冰箱中的苹果按照到期时间按照从小到大排序,很明显的就是说我们希望先吃到期时间早的,才能更好的避免浪费。

    接下来O(n)暴力判断一下这些苹果是否都能吃完,如果能,继续进行,否则输出-1.

    接下来我们按照到期时间从大到小排序,我们希望购买的苹果肯定是越晚到期越好。

    接下来考虑到这样一点:购买的苹果越多,越有可能要浪费掉,所以我们知道这里有一个单调性,我们考虑二分购买的苹果数量。

    对于二分出来的中间值mid,我们暴力处理一次判断能否将这N+mid个苹果都吃完,如果可以,增加购买数量,否则减少购买数量。

    过程维护最后一次可行方案数,然后再输出

    AC代码如下:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 using namespace std;
     5 struct node
     6 {
     7     int date,pos;
     8 }b[1000700];
     9 int a[1000700];
    10 int c[2007000];
    11 int output[2000700];
    12 
    13 int n,m,k;
    14 int cmp(node a,node b)
    15 {
    16     return a.date>b.date;
    17 }
    18 int judge(int a[],int n)
    19 {
    20     int day=0;
    21     int cnt=0;
    22     for(int i=0;i<n;i++)
    23     {
    24         if(day>a[i])return 0;
    25         cnt++;
    26         if(cnt==k)
    27         {
    28             cnt=0;
    29             day++;
    30         }
    31     }
    32     return 1;
    33 }
    34 int Slove(int mid)
    35 {
    36     int tot=0;
    37     for(int i=0;i<n;i++)c[tot++]=a[i];
    38     for(int i=0;i<=mid;i++)c[tot++]=b[i].date;
    39     sort(c,c+tot);
    40     if(judge(c,tot)==1)
    41     {
    42         for(int i=0;i<=mid;i++)
    43         {
    44             output[i]=b[i].pos;
    45         }
    46         return 1;
    47     }
    48     else return 0;
    49 }
    50 int main()
    51 {
    52     while(~scanf("%d%d%d",&n,&m,&k))
    53     {
    54         for(int i=0;i<n;i++)scanf("%d",&a[i]);
    55         for(int i=0;i<m;i++)scanf("%d",&b[i].date),b[i].pos=i+1;
    56         sort(a,a+n);sort(b,b+m,cmp);
    57         if(judge(a,n)==0)
    58         {
    59             printf("-1
    ");
    60             continue;
    61         }
    62         int ans=-1;
    63         int l=0;
    64         int r=m-1;
    65         while(r-l>=0)
    66         {
    67             int mid=(l+r)/2;
    68             if(Slove(mid)==1)
    69             {
    70                 l=mid+1;
    71                 ans=mid;
    72             }
    73             else
    74             {
    75                 r=mid-1;
    76             }
    77         }
    78         printf("%d
    ",ans+1);
    79         for(int i=0;i<ans+1;i++)
    80         {
    81             printf("%d ",output[i]);
    82         }
    83         printf("
    ");
    84     }
    85 }
    View Code

    E题:Morning_X的数论

    这道题的题意不知道有多少人看得懂233,其实很坑的,我完全不知道怎么翻译,所以我就生硬的搬了原来CF上面的题目

    这道题比较适合Home_W做233,不是算法题,是智商题,完全就是考脑洞,所以我题目就提醒了这题是数论题

    题目的意思就是:

    是否有一个等差数列x,x+d,..,x+(n-1)*d,使得其每个元素对m取模后,结果为a1,a2,..,an。如果有,输出首项x和公差d。如果没有,输出-1。多解输出一个即可。

    思路就是:枚举d和a1,来验证所求数列是否满足题意.

    然后在用到两个等差数列的公式:

    1、a1=(sn-n*(n-1)/2*d)/n

    2、Sn^2=n(a1)^2+n(n-1)(2n-1)d^2/6+n(n-1)*d*a1

    在用第一个公式的时候因为涉及到除法取模,所以我们得求一下逆元(代码中fp函数的作用)

    AC代码如下:

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 const int MAXN=100005;
     5 int a[MAXN],b[MAXN];
     6 int fp(int a,int k,int m)
     7 {
     8     int res=1;
     9     while(k)
    10     {
    11         if(k&1)res=1LL*res*a%m;
    12         a=1LL*a*a%m;
    13         k>>=1;
    14     }
    15     return res;
    16 }
    17 int main()
    18 {
    19     int m,n;
    20     scanf("%d%d",&m,&n);
    21     int s[2]={0,0};
    22     for(int i=1;i<=n;i++)
    23     {
    24         scanf("%d",&a[i]);
    25         s[0]=(s[0]+a[i])%m;
    26         s[1]=(s[1]+1LL*a[i]*a[i])%m;
    27     }
    28     if(n==1)return 0*printf("%d 0",a[1]);
    29     if(n==m)return 0*printf("0 1");
    30     sort(a+1,a+n+1);
    31     for(int i=2;i<=n;i++)
    32     {
    33         int d=(a[i]-a[1]+m)%m;
    34         int x=1LL*(s[0]-1LL*n*(n-1)/2%m*d%m+m)*fp(n,m-2,m)%m;//a1=(sn-n*(n-1)/2*d)/n;
    35         //Sn=n(a1)^2+n(n-1)(2n-1)d^2/6+n(n-1)*d*a1
    36         int temp=1LL*n*x%m*x%m;
    37         temp=(temp+1LL*n*(n-1)%m*d%m*x%m)%m;
    38         temp=(temp+1LL*n*(n-1)*(2*n-1)/6%m*d%m*d%m)%m;
    39         if(temp==s[1])
    40         {
    41             b[1]=x;
    42             for(int i=2;i<=n;i++)
    43                 b[i]=(b[i-1]+d)%m;
    44             sort(b+1,b+n+1);
    45             bool isok=1;
    46             for(int i=1;i<=n;i++)
    47                 isok&=(a[i]==b[i]);
    48             if(isok)return 0*printf("%d %d",x,d);
    49         }
    50     }
    51     return 0*printf("-1");
    52 }
    View Code
  • 相关阅读:
    linux 删除已输入的命令行
    LAMP编译参数查看
    mysql忘记密码的重置方法
    cmd大全_练习
    Parallel WebDriver executions using TestNG
    Internet Explorer for Mac the Easy Way: Run IE 7, IE8, & IE9 Free in a Virtual Machine
    linux delete files older than 3 days
    5 commands to check memory usage on Linux
    Base64 Encoding / Decoding in Node.js
    10 Useful du (Disk Usage) Commands to Find Disk Usage of Files and Directories
  • 原文地址:https://www.cnblogs.com/tijie/p/6435175.html
Copyright © 2011-2022 走看看