F. 试题F:你好,2020 15'
描述
2020年,这个年份很特别,2020从中间分成两个整数,大小形状完全一样。
wlxsq对形如2020的数字很感兴趣(不包括前导零),在1到1200中这样的数字包括11、22、33、44、55、66、77、88、99、1010、1111,共11个,他们的和是2616。
请问,在1到n中,所有这样的数的和是多少?
输入
输入一行包含一个整数n。
输出
输出一行,包含一个整数,表示满足条件的数的和。
样例
输入
1200
输出
2616
提示
【评测用例规模与约定】
对于20%的评测用例,1 ≤ n ≤ 100。
对于50%的评测用例,1 ≤ n ≤ 10^3。
对于80%的评测用例,1 ≤ n ≤ 10^4。
对于100%的评测用例,1 ≤ n ≤ 10^6。
//代码1 #include<stdio.h> int main(){ long i,n,sum; scanf("%d", &n); sum=0; for (i=1;i<=n;i++){ if(10<=i&&i<100){ if(i/10==i%10) sum+=i; } if(1000<=i&&i<10000){ if(i/100==i%100) sum+=i; } if(100000<=i&&i<1000000){ if(i/1000==i%1000) sum+=i; } } printf("%d",sum); return 0; }
//代码2 #include<stdio.h> using namespace std; #include<iostream> #define debug(x) cerr<<#x<<" "<<x<<endl; int n,A,B,a[20],p10[20]={1,10,100,1000,10000,100000,1000000}; int split(int x){ int cnt=0,res=0; for(;x;x/=10) a[++cnt]=x%10; int cct=cnt+1>>1; if(cnt&1){ for(int i=cnt/2;i;i--) res=res*10+9; return res; } for(int i=cnt;i>cct;i--) A=A*10+a[i]; for(int i=cct;i;i--) B=B*10+a[i]; if(A<=B) return A;else return A-1; } int deal(int x){ int cnt=0,t=x; for(;x;x/=10) a[++cnt]=x%10; return t*p10[cnt]+t; } long long ans; int main(){ cin>>n; int sz=split(n); for(int i=1;i<=sz;i++) ans+=deal(i); cout<<ans; return 0; }
H. 试题H:计算器 22'
描述
我们知道,windows自带calc功能。
wlxsq决定制作一个Calc,该Calc具备求解一元一次方程的功能。
为了简化工作,拒绝花里胡哨。这个方程中,只有一个等号"=",零个或多个加号"+"、减号"-",一种小写字母表示未知数。当然,减号也可是负号
方程中并没有括号,也没有除号,方程中的字母表示未知数。
输入
仅一行,表示一个合法的方程,包含“+”、“-”、“=”、数字及小写字母。
输出
仅一行,表示答案,形式为“未知元=答案”。对答案保留3位小数,保证答案的绝对值不超过10000。
样例
输入
2a=1
输出
a=0.500
输入
-5+2x=-10
输出
x=-2.500
提示
【评测用例规模与约定】
对于20%的数据,输入数据没有"+,-"符号
对于100%数据,长度不超过255,数字不超过10000,保证只出现一种小写字母。
//代码1 #include<stdio.h> #include<string.h> #include<sstream> #include<iostream> using namespace std; #define debug(x) cerr<<#x<<" "<<x<<endl; string s,A,B;int a[5];char wz;bool cf; int getc(string &str,int len){ for(int i=0;i<len;i++) if(isalpha(str[i])) return str[i]; return -1; } void del(string &str,int l,int r){ int i; for(i=r-1;i>=l;i--) if(!isdigit(str[i])) break; int num=0,f=1; if(i>=0){ if(str[i]=='-') f=-1;else if(isdigit(str[i])) num=str[i]-'0'; } for(int j=i+1;j<r;j++) num=num*10+str[j]-'0'; if(!num&&(!r||!isdigit(str[r-1]))) num=1; num*=f; a[1]+=num; int li=i<0?0:i; int sz=r-li+1; str.erase(li,sz); } bool read(char *&s,int &x){ bool f=0;x=0; for(;*s<'0'||*s>'9';*s++) if(*s=='-') f=1; for(;*s>='0'&&*s<='9';*s++) x=(x<<3)+(x<<1)+*s-'0'; if(f) x=-x; if(*s) return 1;else return 0; } void deal(string &str){ int len=str.length(); int zm=getc(str,len);if(~zm) if(!cf) wz=zm,cf=1; int now=0; for(int nx=-1;;){ if(str.find(zm,now)==string::npos) break; nx=str.find(zm,now); del(str,now,nx); } len=str.length(); if(len<1) return ; char *snum=(char *)malloc((len+1)*sizeof(char)); for(int i=0;i<len;i++) snum[i]=str[i];snum[len]=0; bool flag=1; for(int x;flag;) flag=read(snum,x),a[2]+=x; // delete snum; } int main(){ getline(cin,s);stringstream sio(s); getline(sio,A,'=');getline(sio,B); deal(A); a[1]=-a[1];a[2]=-a[2]; deal(B); printf("%c=%.3lf ",wz,-(double(a[2])/double(a[1]))); return 0; } /* hack data: input 2+0x-1x=0x-x-2x output x=-1.000 */
1 def solve(eq,var='x'): 2 eq1 = eq.replace("=","-(") + ")" 3 eq1 = eq1.replace("x","*x") 4 eq1 = eq1.replace("+*x","+x") 5 eq1 = eq1.replace("-*x","-x") 6 eq1 = eq1.replace("(*x","(x") 7 if eq1[0] == '*': 8 eq1 = eq1[1:] 9 c = eval(eq1,{var:1j}) 10 #将x = 1j代入算式,结果是-9708+3j 11 if c.real!=0: 12 return -c.real/c.imag 13 else: 14 return 0 15 test = input() 16 ch = 'x' 17 for i in range(len(test)): 18 if ord('a') <= ord(test[i]) <= ord('z'): 19 ch = test[i] 20 test = test.replace(test[i],'x') 21 break 22 print("%s=%.3lf"%(ch,solve(test)))
附 全套题解
A:战疫情 5'
直接枚举x,枚举y,判断x+y是否满足在区间[20000, 21000]范围内,且2*x + 100y是否刚好等于50000,如果是,则统计答案即可。
这道题目是 题库P1047百钱买鸡 的弱化版~
当然,手算也是很香的~
x + y = 20000, 2x + 100y = 50000 可以求出一个x,y
x + y = 21000, 2x + 100y = 50000 也可以求出一个x,y
很明显,方案中y的个数是连续的。
答案: 21
B:行动 5'
这个题目手算很简单!总共2020步,每4步一圈,每一圈横坐标-2,纵坐标+2。刚好505圈.
当然这个题目也可以用循环,循环2020次。
在第i次循环,
如果i\%4=1,则x+i,
如果i\%4=2,则y-i,
如果i\%4=3,则x-i,
如果i\%4=4,则y+i,
答案:-1010 1010
C:莱布尼茨公式 10'
直接一个for循环枚举累加即可。
注意了,C/C++选手,请使用 double!请使用 double!请使用 double!
这次很多同学就是使用float导致精度误差,答案错误!double能够精确到15位小数左右
答案:3.141098
D:价值之和 10'
质数:指在 大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
质因子:能整除给定正整数的 质数
写一个函数function1:
判断一个数的每一位是否包含数字5,
用 x \% 10 == 5 判断, 然后再去掉最后一位
再写一个函数function2:
对于一个给定的数x,判断起质因子的个数。
直接枚举2到x-1,判断是否是质数,是否是x的因子,如果是,则计数+1
这是P1020,P1044 两题的结合
答案:3257
E:数方 15'
很有意思的一道题。比较简单。
这个题目可以手算结合编程求答案。从三位数的四次方数作为出发点,逐个确定。当然,在判断质数,三角数的时候计算量比较大,可以借助计算机,编程快速计算。
当然这个题目,编程写,有趣的很。
9个for循环嵌套,枚举每一个数字,9个数字填好之后,再判断是否满足6个条件,如果满足,则就是答案。
当然,如果不加优化,需要等电脑跑一会就是了~
答案:7 2 9 4 5 7 1 6 9
F:你好,2020 15'
第一道编程大题~
根据数据范围,所以数字要么是2位数,要么是4位数,要么是6位数.
如果i是6位数.则判断i\%1000是否等于[frac{i}{1000}],等于则满足条件。
2位数,4位数的同理
G:最优值 18'
这是一道贪心题
Value的计算和单词长度,首字符,以及单词再排列中的位置有关。
单词长度固定的,首字符也是固定的,可以先计算出来。再根据|ch| * len 的值,越大的则在排列中的位置越靠后,让ID尽可能大。
Java,C/C++选手注意了,这个题目,int型变量是肯定存不下的~
H:计算器 22'
这是一道模拟题~
对于读入的字符串分割。从左到右,按照符号分割。
统计出一个常数的和x,再统计出一个未知数的系数和y。最后x / y即可。
I:对称迷宫 25'
这个题目,最暴力的做法就是直接dfs,会搜索的同学,40\%的分应该要拿到。
就是从左上角(1,1)出发,dfs,找出所有到(n, n)的路径,保存并去重,统计对称路径,计算出来的就是答案。但是只能过40\%的数据~
时间复杂度为卡特兰数,感兴趣的可以研究一下。
对于n<=18,做两遍dfs.
第一遍dfs从(1,1)开始搜索到中点(x+y=1)出,并将路径保存到路径1方案中。
然后再从(n,n)跑到中点,保存路径2。
最后枚举路径1中的路径是否在路径2中出现,且中点一样。
J:因数个数 25'
这个题目,对于40\%的数据,还是比较好拿的。
对于60\%的数据,需要对质数筛法有一定的了解。
对于100\%则是考察的线性筛+桶排序,以及对数据的敏感度。
1、对于20\%的数据。
枚举2到n中的每一个数,然后逐一求出每一个数的因数个数。对因数个数排序,找出第k小的数字即可。
时间复杂度O(n^2)
2、对于40\%的数据,优化一下即可。
在逐一求每一个数的因数时枚举到sqrt{n}即可。
时间复杂度O(nsqrt{n})
3、对于60\%的数据
使用质数筛法的原理,枚举2到n,对于每一个数i,将其倍数都标记+1,表示有i这么一个因数。
然后对每一个数的因数个数进行排序,求出第k小即可。
时间复杂度O(nlogn)
4、对于100\%的数据
考虑线性筛算出 2 到 N 的因数个数。d[n] 表示 n 的约数个数。
设 n=p_1^{a1}*p_2^{a2}…p_k^{ak} , d[n]=(a_1+1)(a_2+1)...(a_k+1)。
设 p[i]表示第 i 个质数,Min[i]表示 i 的最小质因子出现次数 + 1。
1. 当前数i是质数,d[i]=2,Min[i]=1。
2. 线筛过程中,若 i\%p[j]!=0, 则 i 不存在约数 p[j],d[p[j] * i] = 2 * d[i], Min[p[j]*i] = 1
3. 否则,p[j] 为 i 的最小质因子, Min[p[j] * i] = Min[i] + 1。d[p[j] * i] = frac{d[i] * Min[p[j] * i]}{(Min[i] + 1)}
最后对d数组桶排序找出第 k 小,时间复杂度 O(N)
对于N >= 2 * 10^7,质数的个数已经大于k了,所以直接特判就好了~