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 }
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 }
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 }
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 }
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 }