num1:C++
code:#include

include

include

include

using namespace std;
const int p=19260817;
int a[10100];
int b[10100];
char a1[10100];
char b1[10100];
int l1,l2;
int len1,len2;
long long x,y;

long long pow2(long long a,long long b)
{
long long res=1;
for(;b;b>>=1,a=aa%p) if(b&1) res=resa%p;
return res%p;
}

void calculet_1()
{
long long num=0;
for(int i=len1;i<=len1+8;i++)
num*=10,num+=a[i];

num%=p;
for(int i=len1+8;i>=len1;i--)
{
	int now=num%10;num/=10;
	a[i]=now;
}

for(int i=0;i<=8;i++) if(a[len1+i]!=0){len1+=i;break;}

}

void calculet_2()
{
long long num=0;
for(int i=len2;i<=len2+8;i++)
num*=10,num+=b[i];
num%=p;
for(int i=len2+8;i>=len2;i--)
{
int now=num%10;num/=10;
b[i]=now;
}

for(int i=0;i<=8;i++) if(b[len2+i]!=0){len2+=i;break;}

}

signed main()
{
// freopen("testdata.in","r",stdin);
// freopen("1.out","w",stdout);

scanf("%s",a1);
scanf("%s",b1);

// printf("%s\n",b1);
l1=strlen(a1);
l2=strlen(b1);

for(int i=0;i<l1;i++)
  a[i]=a1[i]-'0';
for(int i=0;i<l2;i++)
  b[i]=b1[i]-'0';

while(l1-len1>=10) calculet_1();
while(l2-len2>=10) calculet_2();

for(int i=len1;i<l1;i++) x*=10,x+=a[i];
for(int i=len2;i<l2;i++) y*=10,y+=b[i];
x%=p;y%=p;

// printf("%lld\n",y);
if(x0){puts("0");return 0;}
if(y
0){puts("Angry!");return 0;}

long long ans=pow2(y,p-2);

// printf("%lld\n",ans);
ans=(ans*x)%p;

printf("%lld",ans);
return 0;

}
解题思路:利用模运算的性质和费马小定理来解决大数除法在模 p=19260817 下的计算问题。首先,将输入的大数字符串转换为数组形式,并去除前导零。然后,通过自定义的 calculet_1 和 calculet_2 函数(注意这里可能是 calculate_1 和 calculate_2 的拼写错误),对大数进行必要的处理,确保它们在模 p 下有有效的表示。最后,利用费马小定理计算模逆元,从而完成模运算下的除法,并输出结果。

num2:C++
code:#include

include

include

include

using namespace std;

int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}

int main() {
int t;
cin >> t;
while (t--) {
long long l, r;
cin >> l >> r;

    int count = 0;
    
    for (long long r_prime = l; r_prime <= r; ++r_prime) {
        bool found = false;
        for (long long l_prime = r_prime; l_prime >= l; --l_prime) {
            if (gcd(l_prime, r_prime) == 1) {
                found = true;
                count++;
                break;
            }
        }
        if (!found) continue; 
    }
    
    cout << count << endl;
}

return 0;

}
解题思路:首先读取测试数据组数,然后对于每组数据,读取一个区间范围。接下来,通过双重循环遍历区间内的所有数对,其中外层循环变量从区间左端点到右端点递增,内层循环变量从外层循环变量递减到区间左端点。对于每对数,计算它们的最大公约数,如果最大公约数为1,则这对数互质,计数器加一。最后,输出每组数据中互质数对的总数。这种方法虽然直观,但效率较低,特别是对于大数据集。(但该代码存在一定问题,望指点)

num3:C++
code:#include

include

include

include

using namespace std ;
bool vis[1000005];
int num[6000],tot=0;
void read( void )
{
for(int i=2;i<=800;i++)
if(!vis[i])
{
num[++tot]=i;
for(int j=i*i;j<=800;j+=i)
vis[j]=true;
}

for(int i=801;i<=50000;i++)
for(int j=1;j<=tot;j++)
 if(i%num[j]==0)break;
 else if(num[j]*num[j]>=i){num[++tot]=i;break;}

}
int main()
{
//freopen("prime.in","r",stdin);
//freopen("prime.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
read( );
memset(vis,0,sizeof(vis));
for(int k=1;k<=tot&&num[k]<=sqrt(m);k++)
{
int t=num[k]num[k];
if(t<n)t=n/num[k]
num[k];
if(t<n)
if(t<=m-num[k])t+=num[k];
else continue;

     for(;t<=m;)
     {
        vis[t-n]=true;   
        if(t==num[k])vis[t-n]=false;        
        if(t<=m-num[k])t+=num[k];
        else break;           
     }   
 }
if(n==1)vis[0]=true;
int ans=0;
for(int i=0;i<=m-n;i++)
if(!vis[i])ans++;
cout<<ans;
return 0;

}
解题思路:首先通过埃拉托斯特尼筛法预处理出小于等于50000的素数。接着,对于给定的范围[n, m],利用已筛选出的素数,标记出该范围内所有差为素数的数对(x, y=x+p)中的y值(其中x在[n, m-p]内,p为素数)。特别地,对于每个素数p,从其在n范围内的最小完全平方倍数开始,以p为步长标记,同时排除p本身造成的重复标记。最后,统计未被标记的[n, m]内的数,即为与n构成素数差的数的个数,并输出结果。

num4:C++
code:#include<bits/stdc++.h>
using namespace std;
int x,y,p,ans=1,a;
int main()
{
cin>>x>>y;
if(y%x!=0)cout<<0;
else
{
p=y/x;
a=2;
while(p!=1)
{
while(p%a!=0)a++;
while(p%a==0)p/=a;
a++;ans*=2;
}
cout<<ans;
}
return 0;
}
解题思路:首先读取两个整数x和y,判断y是否能被x整除,若不能则直接输出0。若能整除,则计算商p(即y除以x的结果),接着对p进行质因数分解。在质因数分解过程中,每找到一个质因数a,就将答案ans乘以2(因为每个质因数可以选择出现或不出现两种可能,除非p本身就是质数且等于该质因数,此时不应额外乘以2以避免重复计算)。当p被分解到1时,循环结束,最终输出累乘得到的ans作为x和y的最大公约数的不同质因数个数所对应的可能组合数。

num5:C++
code:#include

include

include

include

include

using namespace std;

long long gcd(long long a, long long b) {
while (b != 0) {
long long temp = b;
b = a % b;
a = temp;
}
return a;
}

long long lcm(long long a, long long b) {
return a / gcd(a, b) * b;
}

int main() {
int n, m;
cin >> n >> m;

vector<long long> a(n);
for (int i = 0; i < n; ++i) {
    cin >> a[i];
}

sort(a.begin(), a.end());

vector<int> best_sequence;
long long current_lcm = 1;

for (int i = 0; i < n; ++i) {
    if (lcm(current_lcm, a[i]) <= m) {
        current_lcm = lcm(current_lcm, a[i]);
        best_sequence.push_back(i + 1);
    } else {
        break;
    }
}

cout << current_lcm << " " << best_sequence.size() << endl;
for (int index : best_sequence) {
    cout << index << " ";
}
cout << endl;

return 0;

}
解题思路:读取整数n(数列长度)和m(限制条件),接着读取n个数存入数组。对这些数进行排序后,尝试依次计算当前最小公倍数(LCM)与数组中每个数的LCM,只要结果不超过m,就更新当前LCM并将该数加入最优序列。一旦某个数的加入导致LCM超过m,就停止搜索。最后,输出找到的最大LCM值、最优序列的长度以及序列中的元素编号。这个过程旨在找到满足LCM限制的最长子序列。(该代码仍存在问题)

num6:C++
code:#include

include

include <unordered_set>

include

include

using namespace std;

vector getDivisors(int num) {
vector divisors;
for (int i = 2; i <= sqrt(num); ++i) {
if (num % i == 0) {
divisors.push_back(i);
if (i != num / i) {
divisors.push_back(num / i);
}
}
}
sort(divisors.begin(), divisors.end());
return divisors;
}

int findGenerator(const vector& arr) {
int minVal = *min_element(arr.begin(), arr.end());
int start = minVal;
const int MAX_ITERATIONS = 1000000;

while (MAX_ITERATIONS--) {
    unordered_set<int> reachable;
    reachable.insert(start);

    bool allReachable = true;
    for (int num : arr) {
        if (reachable.count(num)) continue;

        vector<int> divisors = getDivisors(num);
        bool reachableFromStart = false;
        for (int divisor : divisors) {
            int candidate = start + (num - (num % divisor)) / divisor * divisor - num;
            if (candidate >= 0 && candidate % divisor == 0 && reachable.count(start + candidate / divisor)) {
                reachableFromStart = true;
                break;
            }
        }

        if (!reachableFromStart) {
            allReachable = false;
            break;
        }
    }

    if (allReachable) return start;
    start++;
}

return -1; // 如果没有找到满足条件的x,则返回-1

}

int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
cout << findGenerator(a) << endl;
}
return 0;
}
解题思路:针对每个测试用例,首先读取数列长度和数列元素。然后,定义一个函数findGenerator来寻找一个“生成元”x,使得通过不断加x或x的某个除数倍到自身,可以从x到达数列中的每个元素。这通过检查数列中每个元素是否可从x通过一系列加法操作达到来实现。为了避免重复计算和无效搜索,使用了一个哈希集合reachable来记录已可达的元素。若在一定迭代次数内找到这样的x,则返回它;否则,返回-1表示未找到。此过程旨在解决一个关于数列可达性的问题。(该代码存在一定问题)

感受:此次训练题目难度上升很大,还需要学习进步。

posted on 2025-02-10 21:09  Penson2025cpc  阅读(21)  评论(0)    收藏  举报