第一题:RSA
RSA算法选择两个不同质数的积作为模数。现在有两个正整数A,B,如果它们是不同的质数,则判定为 full credit;否则,如果A⋅B不是任意大于1的整数的平方的整数倍,则判定 partial credit;否则判定为no credit。
输入格式
一行两个正整数A,B。
输出格式
full credit 或 partial credit 或 no credit。
样例1输入
13 23
样例1输出
full credit
样例2输入
3 3
样例2输出
no credit
数据规模
所有数据保证 2≤A,B≤1012。
判断a,b是否相等,如果相等直接输出no credit,因为他们的乘积一定是平方数的倍数。
求出a和b的所有因子,并记录下所有因子的出现次数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 5e2 + 5;
unordered_map<int, int>mymap;
//求出x的全部因数
void check(int x)
{
for (int i = 2; i <= x / i; i++)
{
if (x % i == 0)
{
mymap[i]++;
mymap[x / i]++;
}
}
}
void solve()
{
int a, b;
cin >> a >> b;
if (a == b)
{
cout << "no credit" << endl;
return;
}
check(a);
check(b);
bool flag = false;
for (auto i : mymap)
{
int x = sqrt(i.first);
//如果当前因数出现了两次,或者当前因数已经是某个数得平方数了,输出no credit
if (i.second > 1 || x * x == i.first)
{
flag = true;
break;
}
}
if (mymap.size() == 0)cout << "full credit" << endl;
else if(flag)cout << "no credit" << endl;
else cout << "partial credit" << endl;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
第二题:数组操作
给你一个有n个元素的数组a。你可以对它进行如下操作,次数不限。从一个偶数大小为
2k的数组中选择一些从位置l开始的子数组(1≤l≤l+2⋅k−1≤n,k≥1) ,对于0到k−1(包括)之间的每一个i,将值al+k+i分配给al+i。例如,如果a=[2,1,3,4,5,3],然后选择l=1和k=2,应用这个操作,数组将变成a=[3,4,3,4,5,3]。请找出使数组中所有元素相等所需的最少操作数(可能是零)。
输入格式
输入由多个测试用例组成。第一行输入一个整数 t(1≤t≤2×104)表示测试用例的数量。每个测试用例的包含(n+1)个整数:第一个整数 n(1≤n≤2×105) 表示数组的长度。此后n个整数a1,a
2,...,an(1≤ai≤n) 表示数组的元素。
输出格式
输出t行,每行一个整数表示用给定的操作使数组中所有元素相等所需的最小操作数。
样例输入
5 3 1 1 1 2 2 1 5 4 4 4 2 4 4 4 2 1 3 1 1
样例输出
0 1 1 2 0
数据规模
保证所有测试用例的n之和不超过200000。
题目的意思就是每次可以把后面一个区间的数,赋值给后面相距k个位置的区间,然后我们要把整个数组改成一样的。从后面开始遍历,记录所有和最后一个数相同的个数,记作ans,在此过程种,一旦遇到和最后一个不一样的,我们就直接把这个数改成一样的,修改次数++。
代码:
#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 110;
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], res = 0, ans = 1;
while (ans < n)
{
if (v[ans] == num)ans++;
else
{
res++;
ans *= 2;
}
}
cout << res << endl;
}
return 0;
}
第三题:A-B 数对
给出一串数以及一个数字C,要求计算出所有A−B=C的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。第一行,两个整数N,C。第二行,N个整数,作为要求处理的那串数。
输出格式
一行,表示该串数中包含的满足A−B=C的数对的个数。
样例输入
4 1 1 1 2 3
样例输出
3
数据范围
1≤N≤2×105, 1≤C≤2×105, 题目保证输入的N个数范围小于230。
我们可以在对B排序,在 B 中找到 A - C 的左右边界,做差后累加到最终答案 。
#include<bits/stdc++.h>
using namespace std;
int n,c;
int a[200005];
signed main()
{
ios_base::syncc_with_stdio(false);
cin.tie(NULL);
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;
}
第四题:数位计算
给出一个整数n,请解决下面的问题: 使f(x)=(不超过x且与x具有相同位数的正整数的个数)。求出f(1)+f(2)+...+f(n),结果对998244353取模。
输入格式
一个整数N。
输出格式
一个整数——上面问题的答案,并对998244353取模。
样例输入1
16
样例输出1
73
样例解释:对从1到9的每个x,不超过x且与x具有相同位数的正整数有1,2,..,x,因此,f(1)=1,f(2)=2,...,f(9)=9。对从 到 的每个 ,不超过 且与x具有相同位数的正整数有10,11,..,x因此,f(10)=1,f(11)=2,...,f(16)=7。所以答案为73。
样例输入2
238
样例输出2
13870
样例输入3
999999999999999999
样例输出3
762062362
数据规模
所有数据保证 1≤N<1018,且N是整数。
在x和x-1位数相等的情况下,f(x)=f(x-1)+1,这是一个公差为1的等差数列。而因为每个数位的f最小都是1(比如f(1),f(10),f(100)等),所以这就是个首项为1,公差为1的等差数列,当然前提是数位相同的情况下,那我们只要算出每个数位的等差数列前n项和即可,如果题目给的N不够当前数位的最大值了,那就以N做尾。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int MOD = 998244353;
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
unsigned long long n, res = 0, num = 0, power = 10;
cin >> n;
while (1)
{
if (n > power - 1)
{
ll x = (1 + power - power / 10) % MOD;
ll y = ((power - power / 10)) % MOD;
res =res+ (x*y/2)%MOD;
res %= MOD;
}
else
{
ll x = (1 + n - power / 10 + 1) % MOD;
ll y = ((n - power / 10 + 1)) % MOD;
res = res+ (x*y/2)%MOD;
res %= MOD;
break;
}
power *= 10;
}
cout << res%MOD << endl;
return 0;
}
第五题:新国王游戏
又到了H国国庆, 国王再次邀请n位大臣来玩有奖游戏。上次国庆被众臣吐槽国王小气后,国王决定今年大方点,改变游戏规则且不再参与游戏,免得被大臣们质疑。首先, 他让每位大臣在左、 右手上面分别写下一个正整数。然后让这n位大臣排成一排。排好队后, 所有的大臣都会获得国王奖赏的若千金币, 每位大臣获得的金币数分别是:排在该大臣后面的所有人的左手上的数的乘积乘以他自己右手上的数。国王希望所有大臣获得的金币数之和最多,所以他想请你帮他重新安排一下队伍的顺序。
简而言之,给定n对数ai,bi,找到一种排列顺序,使得b1×a2∗a3∗…an+b2×a3∗a4∗…an+⋯+
bn最大,求最大值,由于答案可能很大,需要对1000000007取模
输入格式:
第一行,包含一个整数
n。 第二行到第n+1行,包含两个整数ai,bi
输出格式:
输出一行,表示按某种排序后的b1×a2∗a3∗…an+b2×a3∗a4∗…an+⋯+bn的最大值对
1000000007取模的结果
样例输入
2 1 2 3 4
样例输出
10
数据限制
对于100%的数据,保证 1≤n≤106,1≤ai,bi≤230
自定义排序规则。我们可以把左手右手当成数对的两个元素,存入数组里然后自定义一个特殊的排序规则,从而使得排序后的结果最大。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int MOD = 1000000007;
bool cmp(PII a, PII b)
{
return b.second + a.second * b.first < a.second + b.second * a.first;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<PII>v(n);
for (int i = 0; i < n; i++)cin >> v[i].first >> v[i].second;
sort(v.begin(), v.end(), cmp);
ll sum = 1,res=v[0].second;
for (int i = 0; i < n; i++)
{
if(i>0)res = (res + (sum * v[i].second)%MOD)%MOD;
sum = (sum * v[i].first)%MOD;
}
cout << res%MOD << endl;
return 0;
}
第六题:完美数
对于给定的数字a,b,当整数n在十进制下的所有数位都为a或b时,我们称n是“好数”对于好数n
,当n在十进制下每一位的数字之和也为“好数”时,我们称n是一个“完美数”请你求出有多少m位数是“完美数”
输入格式
输入一行三个整数a,b,m, 含义如题面所示 (1≤m≤106,1≤a,b≤9)。
输出格式
输出一行一个整数表示完美数的数量 , 由于答案可能很大 , 请你将答案对109+7 取模
样例输入
5 1 5
样例输出
1
样例解释
只有11111满足要求
完美数是好数各位数加起来仍然是好数,这里好数只有a和b组成,那么各位数之和就是x个a+y个b。我们只要枚举a或b的个数(x或y),然后计算出x*a+y *b,再看这个和是否是好数即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
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;
}
第七题:Lusir的游戏
Lusir正在玩一个古老的基于DOS的游戏。游戏中有N+1座建筑——从0到N编号,从左到右排列。编号为0的建筑高度为0个单位,编号为i的建筑高度为H(i)个单位。 起初,Lusir在编号为0的建筑处。每一步,它跳到下一个(右边)建筑。假设Lusir在第k个建筑,且它现在的能值是E,下一步它将跳到第k+1个建筑。如果H(k+1)>E,那么Lusir就失去H(k+1)−E的能量值,否则他将得到E−H(k+1)的能量值。游戏目标是到达第N个建筑,在这个过程中能量值不能为负数个单位。现在的问题是Lusir至少以多少能量值开始游戏,才可以保证成功完成游戏?
输入格式
第一行输入整数N。 第二行是N个空格分隔的整数,H(1),H(2),…,H(N)代表建筑物的高度。
输出格式
输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。
数据范围
1≤N,H(i)≤105
输入样例1:
5 3 4 3 2 4
输出样例1:
4
根据题意可知,设前一个能量值为k的话,跳跃一次后都会有k+=(k-H(i)),转换式子变成k=2*k-H(i)。这里选用二分法解题。
代码:
#include<bits/stdc++.h>
using namespace std;
vector<int> m;
int n;
int maxnum=-1;
bool judge(int k){
int d=k;
for(int i=0;i<n;i++){
d=2*d-m[i];
if(d>=maxnum)
return true;
if(d<0)
return false;
}
return true;
}
int main(){
ios_base::sync_with_stdio(false);
cin >> n;
for(int i=0;i<n;i++)
{
int t;
cin >> t;
m.push_back(t);
maxnum=max(maxnum,t);
}
int l=0,r=maxnum;
while(l<r){
int mid=(l+r)/2;
if(judge(mid))
r=mid;
else
l=mid+1;
}
cout << r;
return 0;
}
第八题:bfs练习1
给你一个数字a,每次可以选择下面四种操作中的一种:
- 把数字a加上一。
- 把数字a乘以2。
- 把数字a乘以3。
- 把数字a减去一。
问把这个a变成b最少需要多少步。你要回答q个询问,b1,b2,…,bq,输出把a变成b1,b2,…,bq
的最小步数。
输入格式
第一行两个整数a,q。接下来一行q个整数b1,…,bq。
输出格式
输出q个数字,分别表示把a变成b1,b2…,bq的最小步数。
样例输入
3 10 1 2 3 4 5 6 7 8 9 10
样例输出
2 1 0 1 2 1 2 2 1 2
数据规模
对于所有数据,保证1≤a,q,bi≤105。
一个数可以向下衍生出4个不同的样子,它的四个分支又可以各自伸出4个分支。当在这个树上找到我们要转化的目标值时,第一次出现的层数就是它经过操作的次数。
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
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;
}
第九题:01序列2
又是大家最喜欢的01序列问题了呢这次的问题非常的简单,cc觉得一个01序列中两个1之间至少要有k个0,现在他要构造出一个长度为n的01序列,请问他有多少种不同的构造方法这个数字可能会非常大,请你对109+7取模
输入格式
一行,给出两个整数n,k
输出格式
一个整数,代表不同的构造方法数
数据范围
1≤n≤1060≤k<n
样例输入
4 2
样例输出
6
列几个数据就会发现一直在变的其实是1的位置。 只要保证两个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 endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1000050, MOD = 1e9 + 7;
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 n, k;
init();
cin >> n >> k;
int i = 1;
ll res = 1;
while (i <= n - (i - 1) * k)
{
res = (res + C(n - (i - 1) * k, i) % MOD) % MOD;
i++;
}
cout << res << endl;
return 0;
}
第十题:整除光棍
这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、111、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13
整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。
提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。
输入格式
输入在一行中给出一个不以5结尾的正奇数x(x<1000)。
输出格式
在一行中输出相应的最小的s和n,其间以1个空格分隔。
样例输入
31
样例输出
3584229390681 15
每次先让当前光棍数*10+1直到大于所给的数,然后进行除法,s1字符串存储每次光棍数除以x的商,然后看当前num能否整除x,如果能,break;如果不能把num除以x的余数*10+1赋值给num。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
int x,n,l=0,num=1,i=0;
char s1[10000];
cin>>x;
while(num<x){
num=num*10+1;
l++;
}
while(1){
s1[i++]=num/x+'0';
l++;//记录长度
if(num%x==0)
break;
num=num%x*10+1;
}
cout<<s1<<" "<<l;
return 0;
}