第四周集训

T1:RSA

评析:先判断质数,然后分别分解因数,找到相同的就是no credit,否则partical credit,要注意的是可能是两个数各含有相同因数,也有可能这个数自己含有相同因数。

#include<bits/stdc++.h>
using namespace std;
long long a,b,flag1,flag2,flag3,num1[100],num2[100],t1,t2;
int main()
{
	cin>>a>>b;
	for (int i=2;i<=sqrt(a);i++)
	{
		if (a % i==0) flag1=1;
	}
	for (int i=2;i<=sqrt(b);i++)
	{
		if (b % i==0) flag2=1;
	}
	if (flag1==0 && flag2==0 && a!=b) 
	{
		cout<<"full credit";
		return 0;
	}
	if (a==b) 
	{
		cout<<"no credit";
		return 0;
	}
	
	int x=2,y=2;
	while(a>1)
	{
		if (a % x==0)
		{
			a=a/x;
			num1[++t1]=x;
			num1[++t1]=a;
			if ((a)%x==0) x--;
		}
		if (x>sqrt(a)) break;
		x++;
	}
	while(b>1)
	{
		if (b % y==0)
		{
			b=b/y;
			num2[++t2]=y;
			num2[++t2]=b;
			if ((b)%y==0) y--;
		}
		if (y>sqrt(b)) break;
		y++;
	}
	
	sort(num1+1,num1+t1+1);
	sort(num2+1,num2+t2+1);

	for (int i=1;i<=t1;i++)
	{
		for (int j=1;j<=t2;j++)
		{
			if (num1[i]==num2[j] || num1[i]==num1[i+1] || num2[j]==num2[j+1]) 
			{
				flag3=1;
				break;
			}
		}
		//cout<<flag3<<endl;
	}
	for (int i=1;i<=t1;i++)	
	if (num1[i]==num1[i+1]) 
			{
				flag3=1;
				break;
			}
	for (int j=1;j<=t2;j++)
		{
			if (num2[j]==num2[j+1]) 
			{
				flag3=1;
				break;
			}
		}
	if (flag3==1) 
	{
		cout<<"no credit";
	}
	else cout<<"partial credit";
 } 

T2:数组操作

#include<bits/stdc++.h>
using namespace std;
int t,n;
int main()
{
	scanf("%d",&t);
	for (int i=1;i<=t;i++)
	{
		scanf("%d",&n);
		int a[n+5];
		for (int j=1;j<=n;j++) scanf("%d",&a[j]);
		int num=a[n],sum=1,ans=0;
		a[0]=num;
		for (int j=n;j>1;j--)
		{
			if (a[j]==num && a[j-1]!=num)
			{
				ans++;
				j-=sum;
				a[j]=num;
				sum*=2;
				j++;
			}
			else sum++;
		}
		printf("%d\n",ans);
	}
}

T3:A-B数对

评析:显然O2的复杂度不行,那么直接存数组,用空间换时间。

#include<bits/stdc++.h>
using namespace std;
int n,c,a[200005],f[10000000],ans; 
int main()
{
	cin>>n>>c;
	for (int i=1;i<=n;i++)
	{
		cin>>a[i];
		f[a[i]+c]++;
	}
	for (int i=1;i<=n;i++) ans+=f[a[i]];
	cout<<ans;
} 

T4:数位计算

评析:本质上是等差数列求和,只要将这题巨大的数据取模处理即可。

#include <bits/stdc++.h>
using namespace std;
int n,m,t;
unsigned long long ten[19]={0};
long long pl(long long x,int len)
{
    long long n=x-ten[len-1]+1;
    if(len==1)
    {
        return n*(n+1)/2;
    }
    return ((n % 998244353)*((n+1) % 998244353)/2 % 998244353 + pl(ten[len-1]-1,len-1)) % 998244353;
}
int main()
{
    long long x,y;
    int len=0;
    ten[0]=1;
    for(unsigned long long i=1,j=10;i<=18;i++,j*=10)
    {
        ten[i]=j;
    }
    cin>>x;
    y=x;
    while(y!=0)
    {
        len++;
        y/=10;
    }
    cout<<pl(x,len);
}

T5:新国王游戏

#include<bits/stdc++.h>
using namespace std;
unsigned long long ans,n,ad[1000005];
const int MOD=1000000007;
struct node
{
	unsigned long long a,b;
}p[1000005];
bool cmp(node x,node y)
{
	return x.b*(y.a-1)>y.b*(x.a-1);
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%lld%lld",&p[i].a,&p[i].b);
	sort(p+1,p+n+1,cmp);
	ad[n]=1;
	for (int i=n-1;i>=1;i--)
	{
		ad[i]=ad[i+1]*p[i+1].a % MOD;	
	}
	for (int i=1;i<=n;i++)
	{
		ans+=ad[i]*p[i].b % MOD;
		ans %= MOD;
	}
	printf("%lld",ans%MOD);
}

T6:完美数

评析:借鉴了一下大佬才知道思路。

  • 由于数据量过大,需不断取模,而取模与除法相矛盾,我们就需要将除法变为乘法
  • 而n!=n(n-1)!,(n-1)!的逆元=n!的逆元n,我们只需先求出n!,再求n!的逆元,然后递推出i!的逆元,再求n(n-1)…(n-m+1),即可求出取模后的排列组合数
  • 我们还发现找逆元需要用到快速幂,我们知道21000=4500,而$3^9=3^83=9^43$
    也就是说,对于一个幂,当指数为偶数时,偶数减半,底数平方,当指数为奇数时,指数-1后再减半,底数平方,用于计算最终值的1*底数,在计算的时候同时取模,就可以快速求出幂
  • 具体只能尽量记一下模板吧
#include<bits/stdc++.h>
using namespace std;
const int max_m = 1e6;
const int mod_num = 1e9 + 7;

int a, b, m;
long long factorial[max_m + 1];

bool judge(int sum) {
	int t = 0;
	while (sum) {
		t = sum % 10;
		sum /= 10;
		if (!(t == a || t == b)) return false;
	}
	return true;
}

long long pow(long long x, long long y, long long p) {
	long long ret = 1;
	while (y) {
		if (y & 1) ret = ret * x % p;
		x = x * x % p;
		y >>= 1;
	}
	return ret;
}

long long inv(long long x, long long p) {
	return pow(x, p - 2, p);
}

long long cmp(long long m, long long n) {
	return factorial[n] * inv(factorial[m], mod_num) % mod_num * inv(factorial[n - m], mod_num) % mod_num;
}

int main() {
	factorial[0] = 1;
	for (int i = 1; i <= max_m; i++)
		factorial[i] = (factorial[i - 1] * i) % mod_num;

	cin >> a >> b >> m;
	long long ans = 0;
	for (int i = 0; i <= m; i++) {
		int sum = a * i + b * (m - i);
		if (judge(sum)) ans = (ans + cmp(i, m)) % mod_num;
	}
	cout << ans << endl;
	return 0;
}

T7:Lusir的游戏

评析:二分,不算难,要注意到超过最大高度是e必然是行的,所以要找到最大高度,同时不管e是大于还是小于高度,公式都是e=2*e-a[i],那就省的判断了

#include<bits/stdc++.h>
using namespace std;
int x,n,a[100005];
int check(int e)
{
	for (int i=1;i<=n;i++)
	{
		e=2*e-a[i];
		if (e<0) return 0;
		else if (e>x) return 1;
	}
	return 1;
}
int main()
{
	cin>>n;
	for (int i=1;i<=n;i++) 
	{
		cin>>a[i];
		x=max(a[i],x);
	}
	int l=0,r=1e9,mid;
	while(l<r)
	{
		mid=(l+r)/2;
		if (check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
 } 

T8:BFS练习1

评析:BFS模板题,但要注意用vis数组标记,以及不用变时的那个a要清零

#include<bits/stdc++.h>
using namespace std;
queue<int>q;
int a,q1,b,vis[100005],ans[100005];
void bfs(int x)
{
	//memset(ans,-1,sizeof(ans));
	//ans[a]=0;
	q.push(a);
	while(q.size())
	{
		int t=q.front();q.pop();
		if (t+1>=1 && t+1<=100000 && vis[t+1]==0)
		{
			q.push(t+1);
			vis[t+1]=1;
			ans[t+1]=ans[t]+1;
		}
		if (t-1>=1 && t-1<=100000 && vis[t-1]==0)
		{
			q.push(t-1);
			vis[t-1]=1;
			ans[t-1]=ans[t]+1;
		}
		if (t*2>=1 && t*2<=100000 && vis[t*2]==0)
		{
			q.push(t*2);
			vis[t*2]=1;
			ans[t*2]=ans[t]+1;
		}
		if (t*3>=1 && t*3<=100000 && vis[t*3]==0)
		{
			q.push(t*3);
			vis[t*3]=1;
			ans[t*3]=ans[t]+1;
		}
	}
	ans[a]=0;
}
int main()
{
	cin>>a>>q1;
	bfs(a);
	for (int i=1;i<=q1;i++)
	{
		cin>>b;
		cout<<ans[b]<<" "; 
	}
}

T9:01序列2

评析:又是组合数+快速幂,真是头痛

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mode 1000000007
#define N 1000005
ll qpow(ll a, ll b)
{
	ll ans = 1;
	while (b)
	{
		if (b & 1)
		{
			ans = ans * a % mode;
		}
		a = a * a % mode;
		b >>= 1;
	}
	return ans;
}
ll f[N], nif[N];
ll C(ll a, ll b)
{
	return (f[a] * nif[b] % mode * nif[a - b] % mode) % mode;
}
ll n, k;
int main()
{
	cin >> n >> k;
	ll ans = 0;
	f[0] = 1;
	nif[0] = 1;
	for (ll i = 1; i < N; i++)
	{
		f[i] = i * f[i - 1] % mode;
	}
	nif[N - 1] = qpow(f[N - 1], mode - 2);
	for (ll i = N - 2; i >= 1; i--)
	{
		nif[i] = nif[i + 1] * (i + 1) % mode;
	}
	ll cnt = -1;
	while (1)
	{
		cnt++;
		ll x = cnt + (cnt - 1) * k;
		if ( x > n)break;
		if (cnt == 0)
		{
			ans++;
			continue;
		}
		if (cnt == 1)
		{
			ans += n;
			continue;
		}
		ans = (ans + C(n - x+cnt, cnt))%mode;
	}
	cout << ans%mode << endl;
	return 0;
}

T10:整除光棍

评析:事实上是对除法竖式的模拟,我们可以在纸上画一画找找感觉,很显然这题数据量很大,我们要是直接暴力字符串会比较麻烦,但是模拟除法相当于一位一位的去算,大大降低计算量。所以先找到比x大的最小的a,然后一位位落下来往后算即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int x,num=0;
	cin>>x;
	int a=1;
	while(x>a)
	{
		a=a*10+1;
		num++;
	}
	while(1)
	{
		cout<<(a/x);
		a=a % x;
		if (a==0) break;
		a=a*10+1;
		num++;
	}
	cout<<" "<<(num+1);
 } 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值