并不包含全部
第几个幸运数
题意:
只含有质因子3,5,7的是幸运数字,前几个幸运数字是3 5 7 9 15 21 25 27 35 45,
现在问你59084709587505是第几个幸运数字。
思路:
用优先队列存储,每次取出最小值。然后把他乘上3,5,7的结果入队。
记录出队的次数,当出队的是题目要求的数字则计数完成。
注意去重,因为3乘上5可以得到15,5乘上3也可以得到15,不去重答案会错而且爆内存。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int n=59084709587505LL;
priority_queue<int,vector<int>,greater<int> >q;
map<int,int>mark;
q.push(1);
int a[3]={3,5,7};
int ans=0;
while(1){
int x=q.top();
q.pop();
if(x==n)break;
for(int i=0;i<3;i++){
if(!mark[x*a[i]]){
mark[x*a[i]]=1;
q.push(x*a[i]);
}
}
ans++;
}
cout<<ans<<endl;
return 0;
}
明码
题意:
思路:
题目说16x16的像素,每个字节存8位,那么一行就是两个字节,
转成二进制输出即可,程序输入如下:
完整文字为:“九的九次方等于多少?”
输出387420489即可
code(转换):
#include<bits/stdc++.h>
using namespace std;
const int maxm=50;
int a[maxm][maxm];
signed main(){
int T=10;
while(T--){
for(int i=0;i<16;i++){
int x,y;
cin>>x>>y;
int now=0;
for(int j=7;j>=0;j--){
a[i][now++]=(x>>j&1);
}
for(int j=7;j>=0;j--){
a[i][now++]=(y>>j&1);
}
}
for(int i=0;i<16;i++){
for(int j=0;j<16;j++){
if(a[i][j])cout<<a[i][j];
else cout<<' ';
}
cout<<endl;
}
}
return 0;
}
测试次数
题意:
思路:
d[i][j]表示i层j个球最坏运气下需要的最少次数
枚举丢的层数k:
如果k层碎了,则d[i][j]=d[k-1][j-1]
如果k层没碎,那么继续测试k+1到i层,等价于测试1到i-(k+1)+1层,一共i-k层,那么d[i][j]=d[i-k][j]
dp一下就行了
code:
#include<bits/stdc++.h>
using namespace std;
const int n=1000,m=3;
int d[n+5][m+5];
signed main(){
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
d[i][j]=1e9;
}
}
for(int i=1;i<=n;i++){//枚举层数
for(int j=1;j<=m;j++){//枚举数量
for(int k=1;k<=i;k++){//枚举丢的层数
int t=max(d[k-1][j-1],d[i-k][j]);//碎和不碎
d[i][j]=min(d[i][j],t+1);
}
}
}
cout<<d[n][m]<<endl;
return 0;
}
耐摔指数(((
题意:
题目意思和上面的测试次数一样,
但是这题是多组输入,每次输入一个n,表示有n层,3个手机最坏需要测试多少次
数据范围:n<=1e4
解法:
这题的数据范围比上一题大,像上一题一样dp的话会超时。
令F(x)为扔x次在最坏情况下所能测出的最大层数
当只有一个手机的时候:
只能从第一层开始逐层测试,因此F1(x)=x
当有两个手机的时候:
第一个手机随便从那一层开始扔
如果碎了,则第二个手机只能从1开始扔,接下来变为F1(x-1)
如果没碎,则还是两个手机,变成原问题的子问题,接下来所需次数为F2(x-1)
加上刚刚扔的这一层,得到F2(n)=F1(n-1)+1+F2(n-1)+1
三个手机的时候同理:F3(n)=F2(n-1)+1+F3(n-1)+1
递推一下就行了
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e4+5;
int f[maxm];
int ff[maxm];
int fff[maxm];
signed main(){
for(int i=1;;i++){
f[i]=i;
ff[i]=f[i-1]+ff[i-1]+1;
fff[i]=ff[i-1]+fff[i-1]+1;
if(fff[i]>maxm)break;
}
int n;
while(cin>>n){
int ans=0;
while(fff[ans]<n)ans++;
cout<<ans<<endl;
}
return 0;
}
螺旋折线
题意:
思路:
找一下坐标轴上的点的距离规律,然后硬算
方格计数
题意:
思路:
看到数据范围50000,以为N^2暴力不行了,可能有什么数学方法。
过了一会想起来本地跑就行了,虽然很慢但是跑出来还是没问题的。
枚举第一象限内的50000*50000的所有点,判断是否在圆内,统计数量之后乘上4就是答案
答案为7853781044。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
// cout<<"7853781044"<<endl;
// return 0;
int ans=0;
for(int i=1;i<=50000;i++){
for(int j=1;j<=50000;j++){
if(i*i+j*j>50000LL*50000)break;
ans++;
}
}
cout<<ans*4<<endl;
return 0;
}
复数幂
题意:
思路:
直接上java大数,自己写一个复数类就行了。
提交的时候要删掉package!!!
code:
import java.util.*;
import java.math.*;
class Complex{//复数类
BigInteger a,b;//实部和虚部
Complex(BigInteger a,BigInteger b){
this.a=a;
this.b=b;
}
void mul(Complex t) {//this和复数t相乘
BigInteger x=(this.a.multiply(t.a)).subtract(this.b.multiply(t.b));
BigInteger y=(this.a.multiply(t.b)).add(this.b.multiply(t.a));
this.a=x;
this.b=y;
}
}
public class Main{
public static void main(String[] xx) {
Scanner cin=new Scanner(System.in);
int n=123456;
Complex a=new Complex(BigInteger.valueOf(2),BigInteger.valueOf(3));
Complex ans=new Complex(BigInteger.ONE,BigInteger.ZERO);
while(n>0) {
if(n%2==1) {
ans.mul(a);
}
a.mul(a);
n>>=1;
}
//输出实部
System.out.print(ans.a);
//如果虚部是正数则需要输出一个加号
if(ans.b.compareTo(BigInteger.ZERO)>=0)System.out.print("+");
//输出虚部
System.out.print(ans.b);
//记得输出一个i
System.out.println("i");
}
}
字母阵列
题意:
思路:
显然是dfs
要注意的是这题dfs的方向是不能改变的,因为序列的方向固定,
意思是如果一开始是向右走的,那么之后也都要向右走,dfs的过程记录一下方向就行了。
枚举每个点作为起点dfs即可。
答案为41
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=105;
const int n=100;
const string t="LANQIAO";
char s[maxm][maxm];
int a[8]={-1,1,0,0,-1,-1,1,1};
int b[8]={0,0,-1,1,-1,1,1,-1};
int ans;
void dfs(int x,int y,int cur,int dir){
if(s[x][y]!=t[cur])return ;
if(cur==t.size()-1){
ans++;
return ;
}
int xx=x+a[dir];
int yy=y+b[dir];
dfs(xx,yy,cur+1,dir);
}
signed main(){
// cout<<"41"<<endl;
// return 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>s[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<8;k++){
dfs(i,j,0,k);
}
}
}
cout<<ans<<endl;
return 0;
}
倍数问题
题意:
思路:
n很大,O(n3)枚举或者O(n2)的枚举都不行,观察到k只有1e3,显然是按模k余数分类然后处理。
因为只需要取三个数,模k的同余数超过3个的话,把多余的去掉即可(其实也只有模k等于0的数能取到3个,其余最多两个)。
然后遍历0到k-1,枚举当前同余数选择几个,然后去找其他数补全即可。
我的代码最大复杂度为O(3*k2)
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e3+5;
vector<int>g[maxm];
signed main(){
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++){
int x;cin>>x;
g[x%k].push_back(x);//按模k同余分类
}
for(int i=0;i<k;i++){
sort(g[i].begin(),g[i].end(),[](int a,int b){return a>b;});//从大到小排序
if(g[i].size()>=3)g[i].resize(3);//超过3个就把多余的去掉
}
int ans=0;
for(int i=0;i<k;i++){//O(k)
int sum=0;
int cnt=0;//选择的数量
for(int j=0;j<(int)g[i].size();j++){//枚举g[i]选择个数,max=3
sum+=g[i][j];
cnt++;
if(cnt==1){//还需要两个
for(int t=0;t<k;t++){//O(k)
if(t==i)continue;//跳过i自身,因为i选多个的情况上面会循环到
if(g[t].empty())continue;
int temp=sum+g[t][0];
int need=(k-temp%k)%k;
if(need==i)continue;//跳过i自身,因为i选多个的情况上面会循环到
if(need==t)continue;//跳过t自身,因为t选多个的情况也会循环到
for(int v:g[need]){//O(1)
ans=max(ans,temp+v);
break;
}
}
}else if(cnt==2){//O(1)
if((k-sum%k)%k==i)continue;
for(int v:g[(k-sum%k)%k]){
ans=max(ans,sum+v);
break;
}
}else if(cnt==3){//O(1)
if(sum%k==0)ans=max(ans,sum);
}
}
}
cout<<ans<<endl;
return 0;
}
堆的计数
题意:
n<=1e5
思路:
根节点显然已经确定,只能填1
设d[i]为根位置为i的子树的完全二叉堆方案数(这个i不是数字i,而是二叉树的节点编号)
设左子树大小为Lsize,从n-1个点中挑选Lsize个点的方案数为C(n-1,Lsize)
那么d[i]=C(n-1,Lsize)*d[i*2]*d[i*2+1]
dp一下就行了
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
const int mod=1e9+9;
int fac[maxm];
int sz[maxm];
int d[maxm];
int n;
int ppow(int a,int b,int mod){
int ans=1%mod;a%=mod;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int C(int n,int m){
if(m>n||m<0)return 0;
int up=fac[n];
int down=fac[m]*fac[n-m]%mod;
return up*ppow(down,mod-2,mod)%mod;
}
int cal(int x){//计算每个位置子树大小
if(x>n)return 0;
return sz[x]=cal(x*2)+cal(x*2+1)+1;
}
int dp(int x){
if(sz[x]<=1)return 1;
if(d[x])return d[x];
return d[x]=C(sz[x]-1,sz[x*2])*dp(x*2)%mod*dp(x*2+1)%mod;
}
signed main(){
cin>>n;
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
sz[1]=n;
cal(1);
cout<<dp(1)<<endl;
return 0;
}