目录
T1 RSA
思路:
用map分别存储A和B的因子和过程中出现数,最后若俩个map均为空则说明这两个数为质数,当然首先先要判断这两个数字是否相等,如果相等那么毫无疑问是no credit,如果不相等的话则为full credit,同时如果map不为空则需要遍历map,如果有个数map的值大于等于2的话,或者为某个数的平方则输出no credit,其他的则输出partial credit。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ULL unsigned long long
map<int, int >mp;
void check(ULL a)
{
for (ULL i = 2; i <= sqrt(a); i++)
{
if (a % i == 0)
{
mp[i]++;
mp[a / i]++;
}
}
}
int main()
{
ULL a, b;
cin >> a >> b;
check(a);
check(b);
bool flag = false;
if (a == b)
{
cout << "no credit" << endl;
return 0;
}
for (auto i : mp)
{
int x = sqrt(i.first);
if (i.second >= 2 || x * x == i.first)
{
flag = true;
break;
}
}
if (mp.size() == 0)
{
cout << "full credit" << endl;
}
else if(flag)
{
cout << "no credit" << endl;
}
else
{
cout << "partial credit" << endl;
}
return 0;
}
T2:数组操作
思路:
很容易知道只能将后面的往前赋值,所有如果要相等的话,则必须是全部和最后一个相等,则我们不妨从后面开始遍历,用now来表示目前从后遍历一共有的最后的那个数,用ans来表示一共覆盖了多少次,如果遇到等于最后一个数的数则now++,如果遇到不等于最后一个的数,则now*=2来表示往前覆盖now个,并且ans++,最后当now>所包含的数即可
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--)
{
int n; cin >> n;
vector<int >V(n);
for (int i = n-1; i>=0; i--)
{
cin >> V[i];
}
int num = V[0], ans = 0, now = 1;
while (now<n)
{
if (V[now] == num)
{
now++;
}
else
{
now *= 2;
ans++;
}
}
cout << ans <<'\n';
}
return 0;
}
T3:A-B数对
思路:
一道很基础的双指针问题,首先对所输入的数进行排序,用l来指向每一个需要判断的数字,而r1来寻找a[r1]-a[l]<c最靠右边的那个数的右边第一个数,r2则为恰好满足a[r2]-r[l]>c最靠左边的那个数,则r2-r1则为l满足该该数对的总数,同时因为排序后,满足单调性,则两指针不需要刷新,且当其中一个指针大于n,或者所有数都判断完后循环结束
代码:
#include<bits/stdc++.h>
using namespace std;
int n, c;
int a[200005];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> c;
for (int i = 1; i <= n; ++i)
cin >> a[i];
sort(a + 1, a + 1 + n);
long long ans = 0;
int r1 = 1;
int r2 = 1;
for (int l = 1; l <= n; ++l) {
while (r1 <= n && a[r1] - a[l] < c)
++r1;
while (r2 <= n && a[r2] - a[l] <= c)
++r2;
if (a[r1] - a[l] == c && a[r2 - 1] - a[l] == c)
ans += r2 - r1;
}
cout << ans << endl;
return 0;
}
T4:数位计算
思路:
采用递推,例如对于100以上1000以下的部分可以对其分割为1到9,10到99,100到999分别进行运算后求和,利用等差数列求和公式。
代码:
#include<bits/stdc++.h>
using namespace std;
const long long MOD = 998244353;
unsigned long long f[19];//f[i]表示大于10^i次方
int main()
{
unsigned long long n, power = 10, ans = 0;
cin >> n;
while (true)
{
if (n == 10 && power == 10)
{
ans = 46;
break;
}
else if (power == 10 && n <= power)
{
ans += (n + 1) * n / 2;
break;
}
else if (n > power && power == 10)
{
ans += 45;
}
else if (n > power && power != 10)
{
unsigned long long x = (power - power / 10) % MOD;
unsigned long long y = (power + 1 - power / 10) % MOD;
ans += (x * y) / 2 % MOD;
}
else if (n < power && power != 10)
{
unsigned long long x = (n + 2 - power / 10) % MOD;
unsigned long long y = (n + 1 - power / 10) % MOD;
ans += (x * y) / 2 % MOD;
break;
}
power *= 10;
}
cout << ans % MOD << endl;
return 0;
}
T5:新国王游戏
思路:
首先因为n<=1e6如果挨个遍历那么时间复杂度为n^2肯定会超时,如果我们仔细观察可以发现该求和为(((((b1+0)*a2)+b2)*a3)+b3)*a4.....以此类推,则可以将求和的时间复杂度降低为n,且根据前面观察可知如果调换其中俩个人的位置u[i]和u[i+1]的话,i前面的是不会受到影响的,但是要确保该排序是最大值的排序就要满足调换前大于调换后即可,则为b[i]*a[i+1]+b[i+1]>b[i+1]*a[i]+b[i]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const ll maxn=1e6+5;
typedef struct
{
ll a,b;
}u;
u ar[maxn];
bool cmp(u x,u y)
{
return x.b*(y.a-1)>y.b*(x.a-1);
}
int main(void)
{
ll n,i,ans;
scanf("%lld",&n);
for(i=0;i<n;i++)
scanf("%lld%lld",&ar[i].a,&ar[i].b);
sort(ar,ar+n+1,cmp);
ans=0;
for(i=1;i<=n;i++)
{
ans=(ans*ar[i].a+ar[i].b)%mod;
}
printf("%lld\n",ans);
return 0;
}
T6:完美数
思路:
不妨逆向思维与其挨个遍历,不如设有i个a,n-i个b,只需要满足a*i+(n-1)*b所得到的数字也为完美数,再通过组合数求解即可
const int MOD = 1e9 + 7, N = 1e6 + 10;
ll fact[N], infact[N];
ll qmi(int a, int b)//快速幂
{
ll res = 1;
while (b)
{
if (b & 1) res = res * a % MOD;
a = a * (ll)a % MOD;
b >>= 1;
}
return res;
}
void init()
{
//正求
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++)
fact[i] = fact[i - 1] * i % MOD;
//反求
infact[N - 1] = qmi(fact[N - 1], MOD - 2);
for (int i = N - 2; i; i--)
infact[i] = infact[i + 1] * (i + 1) % MOD;
}
int C(int a, int b)
{
return (fact[a] * infact[b] % MOD * infact[a - b] % MOD) % MOD;
}
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
typedef long long ll;
const int MOD = 1e9 + 7, N = 1e6 + 10;
ll fact[N], infact[N];
ll qmi(int a, int b)//快速幂
{
ll res = 1;
while (b)
{
if (b & 1) res = res * a % MOD;
a = a * (ll)a % MOD;
b >>= 1;
}
return res;
}
void init()
{
//正求
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++)
fact[i] = fact[i - 1] * i % MOD;
//反求
infact[N - 1] = qmi(fact[N - 1], MOD - 2);
for (int i = N - 2; i; i--)
infact[i] = infact[i + 1] * (i + 1) % MOD;
}
int C(int a, int b)
{
return (fact[a] * infact[b] % MOD * infact[a - b] % MOD) % MOD;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int a, b, m;
cin >> a >> b >> m;
init();
char c = a + '0', d = b + '0';
int x;
ll res = 0;
for (int i = 0; i <= m; i++)
{
x = m - i;
ll num = x * a + i * b;
bool flag = true;
while (num)
{
if (num % 10 != a && num % 10 != b)
{
flag = false;
break;
}
num /= 10;
}
if (!flag)continue;
res = (res + C(m, i)) % MOD;
}
cout << (res % MOD) << endl;
return 0;
}
T7:Lusir的游戏
思路:
其实就是一个简单的二分答案,首先很容易知道要通过只需要满足大于最高建筑高度即可,则二分答案的有边界很容易就找到了, 而左边界既可以是最小值(这道题没有hank掉部分数据)也可以是0(最好设为0)
代码:
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int n;
int maxn = -1e9, minn = 1e9;
bool check(int x)
{
for (int i = 1; i <= n; i++)
{
if (a[i] > x)
{
x -= (a[i] - x);
}
else if(a[i]<=x)
{
x += (x - a[i]);
}
if (x < 0)return false;
if (x >= maxn)
{
return true;
}
}
if (x >= 0)return true;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
maxn = max(a[i], maxn);
minn = min(a[i], minn);
}
int L = minn, R = maxn;
while (L<R)
{
int mid = (L + R ) / 2;
if (check(mid))
{
R = mid;
}
else
{
L = mid+1;
}
}
cout << L << endl;
return 0;
}
T8:BFS练习1
思路:
就是一个简单的BFS,只不过需要标记走过的路,以免出现重复
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300050;
int a[N], f[N];
inline int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
void write(int x) {
if (x > 9) write(x / 10);
putchar(x % 10 | '0');
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, num;
num = read(), n = read();
vector<int>v(n);
for (int i = 0; i < n; i++)
{
v[i] = read();
a[v[i]] = -1;
}
queue<int>que;
que.push(num);
int res = 0;
while (!que.empty() && n)
{
int len = que.size();
for (int i = 0; i < len; i++)
{
int ans = que.front();
que.pop();
if (a[ans] == -1)
{
a[ans] = res;
n--;
}
if (ans * 3 < 100050 && f[ans * 3] == 0)
{
que.push(ans * 3);
f[ans * 3] = 1;//判断是否来过减少时间
}
if (ans * 2 < 100050 && f[ans * 2] == 0)
{
que.push(ans * 2);
f[ans * 2] = 1;
}
if (ans - 1 > 0 && f[ans - 1] == 0)
{
que.push(ans - 1);
f[ans - 1] = 1;
}
if (ans + 1 < 100050 && f[ans + 1] == 0)
{
que.push(ans + 1);
f[ans + 1] = 1;
}
}
res++;
}
for (auto i : v)
{
write(a[i]);
putchar(' ');
}
return 0;
}
T9:01序列2
思路:
排列中一直在变的其实是1的位置,0的位置不重要,我们只要保证两个1之间有k个0就行,剩下的位置可以随便排列。那我们就从0枚举1的数量i,然后剩下的位置全塞0就行,但0的数量最少要有(i-1)* k。为了方便其实我们可以忽略掉0,即把1都挨着,只要我们默认两个1之间有k个0就行,这样剩下01串的长度就是n-(i-1) * k,我们只要算在这个长度下,1能有多少种不同的排序即可。前面已经涉及到了组合数这里就不加赘述了
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MOD = 1e9 + 7,N= 1000005;
LL qumi(LL a, int b)
{
LL ans = 1;
while (b)
{
if (b & 1)
{
ans = ans * a % MOD;
}
a = a * a % MOD;
b >>= 1;
}
return ans;
}
LL fact[N], infact[N];
void init()//初始化
{
fact[0] = infact[0]=1;
for (int i = 1; i < N;i++)
{
fact[i] = fact[i - 1] * i % MOD;
}
infact[N-1] = qumi(fact[N-1], MOD - 2);
for (int i = N - 2; i; i--)
{
infact[i] = infact[i + 1] * (i + 1) % MOD;
}
}
LL C(LL a, LL b)
{
return fact[a] * infact[b] % MOD * infact[a - b]%MOD;
}
int main()
{
init();
int n, k;
cin >> n >> k;
int i = 1;
LL res = 1;//算上一个1没有的情况
while (i<=n-(i-1)*k)
{
res = (res + C(n - (i - 1) * k, i)) % MOD;
i++;
}
cout << res << endl;
return 0;
}
T10:整除光棍
思路:
这是一道模拟题,模拟除法,首先找到大于n的最小光棍,然后再除以n余的数假设为a,则a*10+1,再次除以n直到最后余0为止
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
int a = 1,num=1;
while (a<n)
{
a = a * 10 + 1;
num++;
}
while (true)
{
cout << a / n;
a = a % n;
if (a==0)
{
break;
}
a = a * 10 + 1;
num++;
}
cout <<" " << num << endl;
return 0;
}