本人大二,第一次参加蓝桥杯国赛,虽然有过一年多的acm经历,还是没有什么信心,本来想着水一个国三,没想到可以拿国一,这波不亏。
以下想法,答案不能保证正确,仅供参考。
A题
题意:给你2张100元,要你换成5元,2元,1元的零钱,要求是2元的张数是1元的10倍,并且5元,2元,1元张数不能为0,都得有。
思路:简单题,列方程发现只有一个解,19张5元,50张2元,5张1元。
答案 : 74
B题
题意:有一排n个烟花,要你来点有几种点法,要求是不能点两个连续的烟花。
比如当n=3,有5种点法。现在告诉你n=30,有几种点法?
思路:直接dfs搜即可。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
int sum = 0;
void dfs(int dep,int p)
{
if(dep == 30){
sum++;
return;
}
if(p == 0){
dfs(dep + 1,0);
dfs(dep + 1,1);
}
else{
dfs(dep + 1,0);
}
}
int main()
{
dfs(0,0);
cout << sum << endl;
return 0;
}
答案:2178309
C题 代码填空题
题意:是关于格雷码的题目,题意很长,主要意思是给你一个整数a,你要把它二进制1最先出现的位置的后一位更改(1变0,0变1)。比如,1101 -> 1111 , 01 -> 11,11 -> 01。
思路:lowbite的知识。a & -a 可以得到类似于000100,其中1就是最先出现的1,其中原理模拟一遍就可得出。之后向后移一位再与a异或即可得到结果。
答案:((a & (-a)) << 1) ^ a
D题 程序设计题
题意:有一块电子表能显示0到n - 1,它有两个按键,分别能让时间加1和k(可循环),现在给你n和k,问你从任意时间调到任意时间有个最少操作数,要你输出所以最少操作数中最大的那一个。
输入:n k
输出:按题目要求输出
样例
输入:5 3
输出:2
样例解析
距离 操作
0 0
1 1
2 1 + 1
3 3
4 1 + 3
最多两步,输出2
思路:我是dp做的,dp[i] = min(dp[(i - 1 + n) % n],dp[(i - k + n) % n]) + 1
答案:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define INF 10000000
using namespace std;
int dp[100008];
int main()
{
int n,k;
while(scanf("%d%d",&n,&k) != EOF){
for(int i = 0;i <= n;i++){
dp[i] = INF;
}
dp[0] = 0;
int maxn = 0;
for(int i = 1;i < n;i++){
dp[i] = min(dp[(i - 1 + n) % n],dp[(i - k + n) % n]) + 1;
maxn = max(maxn,dp[i]);
}
cout << maxn << endl;
}
return 0;
}
E题 程序设计题
题意:
思路:不会做
答案:听说是dp题,完全不会
F题 程序设计题
题意:给你一个n*n的矩阵,其中第i行第j列 a[i][j] = gcd(i,j) * gcd(i,j)
n=4时
1 1 1 1
1 4 1 4
1 1 9 1
1 4 1 16
现在给你一个n,要你输出矩阵内所有元素的和
输入:一个整数n(0 < n < 1e7)
输出:按题目要求输出
样例1
输入:4
输出:48
样例2
输入:6
输出:155
思路:易知矩阵上三角=下三角,主对角线好求,所有我们的任务主要是求上三角。
上三角 = 求和gcd(i,j)平方(1<= j <= n,1<= i < j)
现在我们来考虑这样一个问题,给你一个n要你求和gcd(i,n)(1 <= i < n)你会怎么求,正解就是先求出所有n的约数x,然后求和 x * euler[n / x](euler 是欧拉函数)。
来证明:设gcd(i,n) = x,那么gcd(i / x,n / x) = 1,说明x是n的约数,i / x 与n / x互质,也就是说对于这个x,它出现的次数为与n / x互质数的个数,即euler[n / x]。所以,对于这个约数x它对结果做的贡献 = x * euler[n / x]。
现在我们重新回到求上三角的问题中来,其实就是刚才问题的拓展,对于每个j求和gcd(i,j)平方(1 <= i < j) ,但我们不能对每个j求它的约数,会超时。那么我们就以约数为主,对一个数x,它是2x的约数,是3x的约数.....当循环到2x时,我们就要加上x * x * euler[2],到3x时,加上x *x * euler[3]....。所以x对结果的贡献就是 = x * x * (euler[2] + euler[3]....+euler[n / x])。我们可以预处理一个数组记录这个前euler和,这样时间复杂度就是O(n)了。
答案:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define LL long long
using namespace std;
const int maxn = 1e7+10;
const int mod = 1e9+7;
LL euler[maxn];
LL sum[maxn];
void Init()
{
memset(euler,0,sizeof(euler));
euler[1] = 1;
for(int i = 2; i < maxn; i++)
{
if(!euler[i])
{
for(int j = i; j < maxn; j+=i)
{
if(!euler[j])
euler[j] = j;
euler[j] = euler[j]/i*(i-1);
}
}
}
sum[1] = 0;
for(int i = 2; i < maxn; i++)
sum[i] = (sum[i-1]+euler[i])%mod;
}
int main()
{
Init();
int n;
LL answer = 0;
while(scanf("%d",&n)!=EOF){
answer = 0;
for(int i = 1; i <= n/2; i++)//求上三角
{
LL ans = i;//不能直接写i*i,会爆int
ans = (ans * ans) % mod;
answer = (answer+ans*sum[n/i])%mod;
}
answer = answer*2%mod;
for(int i = 1; i <= n; i++)//求对角线
{
LL ans = i;
ans = (ans * ans) % mod;
answer = (answer+ans)%mod;
}
cout<<answer<<endl;
}
return 0;
}//田长宏编码