第五(??)次个人赛

Like 1 + 1(大数乘法取模)

Description
求 a 乘 b 对 p 取模的值,其中1<=a,b,p<=1e18。
Input
第一行a,第二行b,第三行p。
Output
一个整数,表示a*b%p的值。
AC代码
把乘法转化为加法计算。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a,b,p;
int main()
{
	cin>>a>>b>>p;
	
	//把乘法变为加法
	//a*b = (a+a+a+......+a)(b个a相加) 
	int res=0;
	while(b)
	{
		if(b&1)	res=(res+a)%p;
		b>>=1;
		a=(a+a)%p; 
	}
	
	cout<<res<<endl;
	return 0;
}

数学题(完全背包??)

Description
Wsc学长最近刚参加了数学竞赛荣获一等奖,正准备向Wmx学长去炫耀炫耀,此时Wmx学长正被一道数学题困惑可没心思关心奖牌,直接将题目丢给Wsc学长,看到题目Wsc学长也一头雾水,想请你帮帮忙…
题目描述:给你一个正整数n,现规定n只能由双重平方数相加得到,请你找到最少的双重平方数来组成n。例如,n = 17,17 =1^4+2^4 ,没有更少的双重平方数可以相加组成17,则答案是2。
Input
输入一行,一个正整数n。(0<n<=1e5)
Output
输出一行,包括一个整数表示最少需要的双重平方数个数。
AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n;
int num[N],dp[N+10];
int main()
{
	scanf("%d",&n);
	int cnt=0;
	for(int i=0;;i++)
	{
		num[i]=(ll)i*i*i*i;
		dp[num[i]]=1;
		cnt++;
		if(num[i]>=N)	break;
	}
	for(int i=0;i<N;i++)	
		dp[i]=i;
	
	for(int i=0;i<cnt;i++)
	{
		for(int j=0;j<=n&&j+num[i]<=n;j++)
			dp[j+num[i]]=min(dp[j+num[i]],dp[j]+1);
	}
	printf("%d\n",dp[n]);
	return 0;
}

字符串中不同字串的种类数(str.substr(pos,len))

Input
输入一行,包括一个字符串s(0<len(s)\leq15000<len(s)≤1500)
Output
一行,一个整数,表示字符串有多少种不同字串
AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int N=2e5+10;
string s;
map<string,int> mp;	//记录是否出现过 
ll ans;
int main()
{
	cin>>s;
	int n=s.size();
	for(int i=1;i<=n;i++)	//长度 
	{
		mp.clear();		//不同长度字符串肯定不相等 
		// 这里不清空map会MLE 
		for(int j=0;j+i-1<n;j++)	//起点
		{
			string temp=s.substr(j,i);
			// str.substr(pos,len) 在字符串str下标pos处向后截取长度为len的字符串 
			if(mp[temp]==0)	ans++;
			mp[temp]=1;
		} 
	}
	cout<<ans<<endl;
	return 0;
}

斐波那契(矩阵快速幂)

Description
这是一个加强版的斐波那契数列。给定递推式:

f[0]=0
f[1]=1
f[i]=f[i-1]+f[i-2]+i^3+i^2+i+1

求f[n]的值,这个值可能很大,请对10^9+7取模。
Input
输入一行,包括一个整数n(0<=n<=1e18)
Output
输出一行,包括一个整数f[n]对10^9+7取模
AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n;

struct Matrix
{
	ll m[6][6];
};

Matrix multi(Matrix a,Matrix b)	//矩阵乘法 
{
	Matrix res;	 
	for(int i=0;i<6;i++)	//初始化 
	{
		for(int j=0;j<6;j++)
			res.m[i][j]=0;
	}
	
	for(int i=0;i<6;i++)
	{
		for(int j=0;j<6;j++)
		{
			for(int k=0;k<6;k++)
			{
				res.m[i][j]+=b.m[i][k]*a.m[k][j];
				//注意相乘顺序 
				//这里写的是a的第j列乘以b的第i行 
				res.m[i][j]%=mod;
			}
		}
	}
	return res;
}

Matrix qpow(Matrix a,ll k)	//矩阵快速幂 
{
	Matrix res;
	//初始化为单位矩阵 
	for(int i=0;i<6;i++)
	{
		for(int j=0;j<6;j++)
		{
			res.m[i][j]=0;
			if(i==j)	res.m[i][j]=1;
		}
	}
	
	while(k)
	{
		if(k&1)	res=multi(res,a);
		a=multi(a,a);
		k>>=1;
	}
	
	return res;
}

Matrix a,b;
Matrix ans;
ll anss;
//全局变量初始值为0 

int main()
{
	cin>>n;
	if(n==0)	anss=0;
	else if(n==1)	anss=1;
	else
	{
		//初始化矩阵 
		a.m[0][0]=1;a.m[1][0]=0;a.m[2][0]=8;	
		a.m[3][0]=4;a.m[4][0]=2;a.m[5][0]=1;
		for(int i=0;i<6;i++)	b.m[0][i]=1;
		b.m[1][0]=1;b.m[2][2]=1;b.m[2][3]=3;	
		b.m[2][4]=3;b.m[2][5]=1;b.m[3][3]=1;	
		b.m[3][4]=2;b.m[3][5]=1;b.m[4][4]=1;	
		b.m[4][5]=1;b.m[5][5]=1;
		
		ans=multi(a,qpow(b,n-1));
		anss=ans.m[0][0];
	}
	cout<<(anss%mod+mod)%mod<<endl;
	return 0;
}

假简单题(三进制枚举)

n 个砝码,砝码各不相同。
选一部分砝码(可以是0个,也可以是 n 个,也可以是不大于n的任意个),放到天平上。
求让天平左倾、持平和右倾的砝码放置方案数。
Input
第一行,一个整数 n
第二行,n 个整数,表示砝码的质量
Output
输出一行三个整数,分别表示让天平左倾、持平和右倾的砝码放置方案数。
AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N =20;
int n;
ll a[N];
int ans1,ans2,ans3;

int main()
{
	cin>>n;
	int st=1;	//状态数量 
	for(int i=1;i<=n;i++)	
	{
		cin>>a[i];
		st*=3;	//每个物品有放左边放右边和不放三种状态 
	}
	for(int i=0;i<st;i++)	//三进制枚举所有状态,时间复杂度O(n^3) 
	{
		int temp=i;
		ll sum=0; 	//左边重量与右边的差值 
		for(int j=1;j<=n;j++)	//枚举所有砝码 
		{
			if(temp%3==1)	sum+=a[j];	//砝码放左边 
			else if(temp%3==2)	sum-=a[j];	//右边 
			temp/=3;	//下一物品 
		}
		if(sum>0)	ans1++;
		else if(sum==0)	ans2++;
		else	ans3++;
	}
	cout<<ans1<<' '<<ans2<<' '<<ans3<<endl;
	return 0;
}

仅仅是位运算(位运算)

Description
众所周知,位运算有与,或,异或三种。
与:相同位的两个数字都为 1,则为 1;若有一个不为 1,则为 0。
或:相同位只要一个为 1 即为 1。
异或:相同位不同则为 1,相同则为 0 。
小 W 觉得她们非常的有趣,为了体现自己的强大,小 W 一口气学会了三种运算,并出了一道题准备考考你。给出 l,r 以及运算 X ,询问 [l,r] 的每一个数通过 X 运算后的值。
其中运算会给出,op=1op=1 运算为与,op=2op=2 运算为或,op=3op=3 运算为异或
Input
第一行给出n,表示询问个数。
接下来n行,每行给出l , r , op,分别代表询问的区间范围以及运算类型。
Output
输出n个整数,表示运算后的答案。
AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
int n;
ll l,r,op;

ll solve1(ll l,ll r)	// 区间与运算 & 
{
	ll res=r;
	int x=0;	// 标记 最左边的 相同位 数字不同 的位置 
	for(int i=1;r!=0;i++)		// 从右往左扫描 
	{
		if((l&1)^(r&1))		// 分别取l和r的最后一位,如果数字不同 
			x=i;			// 更新
			
		l>>=1;	// 右移操作 		1110011 ==> 111001 
		r>>=1;	// 把已经判断过的位置(即最后一位)删去 
	}
	
	res>>=x;	// 先右移x位,再向左移x位 
	res<<=x;	// 这样就把后x位的所有数字置0 
				// 也就是把res的后x位清零 
	
	return res;
}

ll solve2(ll l,ll r)	//区间或运算 
{
	ll res=r;
	int x=0;
	for(int i=1;r!=0;i++)
	{
		if((l&1)^(r&1))
			x=i;
		l>>=1;
		r>>=1;
	}
	
	if(x!=0)
		res|=(((ll)1<<x)-1);	//记得这里的1要强制转换 
		// 注意这里或运算是 | ,不是 ||
		// 1左移x位再减一就变成了x个1 
		// 再与res进行或运算 就是把res的后x位全变为1
	
	return res;
}

ll solve3(ll l,ll r)	//区间异或
// f(l,r) = f(0,l-1) ^ f(0,r)
// 当 x % 4 = 0 时 f(0, x) = x
// 当 x % 4 = 1 时 f(0, x) = 1
// 当 x % 4 = 2 时 f(0, x) = x + 1
// 当 x % 4 = 3 时 f(0, x) = 0
{
	ll res1=0;	//求f(0,l-1)
	if((l-1)%4==0)	res1=l-1;
	else if((l-1)%4==1)	res1=1;
	else if((l-1)%4==2)	res1=l;
	else if((l-1)%4==3)	res1=0;
	
	ll res2=0;	//求f(0,r) 
	if(r%4==0)	res2=r;
	else if(r%4==1)	res2=1;
	else if(r%4==2)	res2=r+1;
	else if(r%4==3)	res2=0;
	
	return res1^res2;
}

int main()
{
	cin>>n;
	while(n--)
	{
		cin>>l>>r>>op;
		if(op==1)	cout<<solve1(l,r)<<endl;
		else if(op==2)	cout<<solve2(l,r)<<endl;
		else if(op==3)	cout<<solve3(l,r)<<endl;		
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值