1.跳跃
直接判断前后是否有刺激跳跃即可
#include<iostream>
using namespace std;
const int N=100010;
int a[N];
int main()
{
int n,k;
int cnt=0;
cin >> n >> k;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
}
for(int i = 2; i <= n ;i ++)
{
if(a[i]>a[i - 1]*k||a[i]*k<a[i - 1])//判断前后
cnt ++;
}
cout << cnt;
}
2.减法和除法
每次判断哪个操作更小就选哪个
#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
ll n,x;
cin >> n >> x;
ll cnt = 0;
while(n>0)
{
if(n/2<n-x)//判断哪个更小
n=n/2;
else
n-=x;
cnt ++;
}
cout << cnt;
}
3.减法和求余
原本以为这道题只需要对2取余就好了,如果有大于2的数,全部取余为一次操作,剩下如果有数不为0只会是一,还需要一次操作,是零则不需要,但是忽略了一种数据即最大公约数不为1,像11,22,33,44,55,66,77,它们可以通过一次取余变为0,而像我之前那样想就会有两次操作,所以需要特判一下
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
typedef long long ll;
ll a[N];
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int n;
cin>>n;
ll cnt=0;
for(int i = 1; i <= n; i ++)
{
scanf("%lld",&a[i]);
}
ll d=a[1];
for(int i = 1; i <= n; i ++)
{
d=gcd(d,a[i]);
}
if(d>1)//特判
{
cout<<"1";
return 0;
}
sort(a + 1, a +1+ n);
for(int i=1;i<=n;i++)
{
if(a[i]>=2)//有大于的就取余,算一次操作
{
for(int j=i;j<=n;j++)
a[j]=a[j]%2;
cnt++;
}
else
continue;
}
for(int i=1;i<=n;i++)
if(a[i]!=0)//剩下的数中还有1
{
cout<<cnt+1<<endl;
return 0;
}
cout<<cnt<<endl;
}
4.生日
根据题意,总方案数是2^n,因为每个人都可以选择过或者不过。在第 i 天过生日的人有可能是第 i 个人,可能是第 i * 2 个人, 也可能是第 i * 2 + 1 个人,所以会有四种组合方式,若这三天都在n的范围内,则确定了三个人是否选择,还剩下2 ^(n-3)种方案,若 i * 2 + 1 不在范围内,则只会确定两个人是否选择,剩下 2^ (n-2)种方案,如果n>i,一种方案也没有。
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const ll MOD = 1e9 + 7;
int n;
ll a[N];
ll p2[N]; // 预处理 2 ^n
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++)
scanf("%lld", &a[i]);
p2[0] = 1;
for (int i = 1; i <= n ; i++)
p2[i] = (p2[i - 1] * 2ll) % MOD;
ll res = 0;
for (int i = 1; i <= n; i++)
{
if (n < 2 * i) //0方案
break;
else if (n < 2 * i + 1) //确定2个
{
res = res + p2[n - 2] * (a[i] ^ a[2 * i]) % MOD;
res %= MOD;
}
else //确定三个
{
//四种组合方式:12 13 23 123
res = res + p2[n - 3] * ((a[i] ^ a[2 * i]) + (a[i] ^ a[2 * i + 1]) + (a[2 * i + 1] ^ a[2 * i]) + (a[i] ^ a[2 * i] ^ a[2 * i + 1])) % MOD;
res %= MOD;
}
}
printf("%lld", res);
return 0;
}
5.工艺品
这道题我一直在推公式,改了好多次只过了80的样例,结束后看别人的代码发现超简单,然后看题解发现只要按照这个
1.a<=c:鸡尾酒一直在加工
2.a>c: 尽可能多的加工玥玥加工的半成品。
来看就行了,那么能够加工的半成品是,n - c是因为如果在最后小于c的时间内加工完 b 不能作为成品,所以要预留时间,那么总成品为
#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
ll n,a,b,c;
cin >> n >> a >> b >> c;
if(a <= c)
cout << n / a;
else
{
int cnt = (n - c) / (max(b,c));
cout << (n - cnt * c) / a + cnt;
}
}
6.鸡尾酒数
找规律可以发现
个位数没有鸡尾酒数
十位数每十个数可凑出一次鸡尾酒数(19,28,37.....)
百位数每十个数可凑出一次鸡尾酒数
当位数为 n 时,记前 n 位数的和为 last,last 的最后一位一定在0~9范围内,则最后以为填0~9十个数中某一个一定可以凑出鸡尾酒数,所以1~n 的鸡尾酒数初步计算为 n/10-1 个,如果 n 为1231,会有1231/10=123个鸡尾酒数,但如果n=1235,1235/10=123,但实际上有124个鸡尾酒数,所以最后需要特判一下。
上述思路为 n / 10 - 1特判最后是否加一,而下面代码则是判断 n/10 是否需要减一
#include<cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
//const int mod=1e9+7;
const int MAXN = 1e6;
using ll = long long ;
ll n, q;
char s[MAXN];
ll pre[MAXN];
const ll mod = 1e9 + 7;
ll check(ll d, ll lst)
{
if (n == 1 || lst >= 10 - d || d == 0)
return 0;
return 1;
}
int main()
{
scanf("%s %lld", s + 1, &q);
n = (ll)strlen(s + 1);
pre[1] = 1;
for (int i = 2; i <= n+1 ; i++) //10^n
{
pre[i] = pre[i - 1] * 10 % mod;
}
ll dsum = 0, ans = 0;
//ans记录题目中的n/10是多少
for (int i = 1; i <= n - 1; i++)
{
dsum += (s[i] - '0');//数位和
ans = (ans * 10ll + (ll)(s[i] - '0')) % mod;
}
printf("%lld\n", (ans - check(dsum % 10, s[n] - '0') + mod) % mod);
int a, b;
while (q--)
{
scanf("%d %d", &a, &b);
if (a != n) //这一位变成0带来的影响
{
dsum -= s[a] - '0';
ans = (ans - pre[n - a] * (ll)(s[a] - '0') + mod) % mod;
}
s[a] = (b + '0');
if (a != n)//这一位+b带来的影响
{
dsum += b;
ans = (ans + pre[n - a] *(ll) b) % mod;
}
printf("%lld\n", (ans - check(dsum % 10, s[n] - '0') + mod) % mod);
}
return 0;
}