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;
}