简单数列
思路:观察数列可以发现a[n]=a[n-1]*3+a[n-2]*2+a[n-3];
注意题目的数据范围最大为1000,a[100]已经爆long long 了
所以要套用大数乘法和大数加法模板
#include<bits/stdc++.h>
using namespace std;
string add(string a,string b)//只限两个非负整数相加
{
string ans;
int na[1200]= {0},nb[1200]= {0};
int la=a.size();
int lb=b.size();
// 倒叙存储
for(int i=0; i<la; i++)
na[la-1-i]=a[i]-'0';
// 倒叙存储
for(int i=0; i<lb; i++)
nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
// 从个位开始计算
for(int i=0; i<lmax; i++)
{
na[i]+=nb[i];
na[i+1]+=na[i]/10;
na[i]%=10;
}
// 去除前置0
if(!na[lmax])
lmax--;
for(int i=lmax; i>=0; i--)
ans+=na[i]+'0';
return ans;
}
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
const int L=1200;
string s;
int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
fill(na,na+L,0);
fill(nb,nb+L,0);
fill(nc,nc+L,0);//将na,nb,nc都置为0
for(int i=La-1; i>=0; i--)
na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
for(int i=Lb-1; i>=0; i--)
nb[Lb-i]=b[i]-'0';
for(int i=1; i<=La; i++)
for(int j=1; j<=Lb; j++)
nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
for(int i=1; i<=La+Lb; i++)
nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
if(nc[La+Lb])
s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
for(int i=La+Lb-1; i>=1; i--)
s+=nc[i]+'0';//将整形数组转成字符串
return s;
}
int main()
{
string a="1",b="1",c="2";
int n;
scanf("%d",&n);
if(n==1)
puts("1");
else if(n==2)
puts("1");
else if(n==3)
puts("2");
else
{
for(int i=4; i<=n; ++i)
{
string tem=add(add(mul(c,"3"),mul(b,"2")),a);
a=b,b=c,c=tem;
}
cout<<c<<endl;
}
}
整数统计
思路:用数组来统计奇数出现的次数,但一般的数组最大范围1e7左右,所以要用到STL的map,定义map<long long,int>即可解决
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll sca(){
ll su=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))su=su*10+c-'0',c=getchar();
return su*f;
}
map<ll,int>mp;
int main()
{
int n;
scanf("%d",&n);
ll x;
for(int i=1;i<=n;++i)
scanf("%lld",&x),mp[x]++;
int num=0;
for(map<ll,int>::iterator it=mp.begin();it!=mp.end();++it)
if((it->second)&1)++num;
printf("%d\n",num);
}
小h走楼梯
思路:每走一层的期望等于1/P1,例如P1=0.5,也就是说走两步才有可能走到上一层;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll sca()
{
ll su=0,f=1;
char c=getchar();
while(!isdigit(c))
{
if(c=='-')
f=-1;
c=getchar();
}
while(isdigit(c))
su=su*10+c-'0',c=getchar();
return su*f;
}
double a[100005],b;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lf %lf",&a[i],&b);
double ans=0;
for(int i=1;i<n;++i)
ans+=1.0/a[i];
printf("%.3lf\n",ans);
}
最长匹配括号子串
dp[i]表示从s[0]到s[i]包含s[i]的最长的有效匹配括号子串长度。
dp[0]=0;
每次循环
如果s[i]是右括号,跳过前面匹配的括号序列j=i-1-dp[i-1]
判断s[j]是否是匹配的左括号,如果匹配,dp[i]=dp[i-1]+2;注意要加上匹配的左括号的前面是已匹配的括号子串长度。
#include <bit/stdc++.h>
using namespace std;
#define ll long long
char s[100010];
int dp[100010];
int solve1()
{
int maxn = 0,len=strlen(s);
for(int i = 0; i < len; i++)
dp[i] = 0;
for(int i = 1; i < len; i++)
{
if(s[i] == ')')
{
int j = i-1-dp[i-1];
if(j >= 0 && s[j] == '(')
{
dp[i] = dp[i-1] + 2;
if(j-1 >= 0)
dp[i] += dp[j-1];
}
}
if(s[i] == ']')
{
int j = i-1-dp[i-1];
if(j >= 0 && s[j] == '[')
{
dp[i] = dp[i-1] + 2;
if(j-1 >= 0)
dp[i] += dp[j-1];
}
}
if(s[i] == '}')
{
int j = i-1-dp[i-1];
if(j >= 0 && s[j] == '{')
{
dp[i] = dp[i-1] + 2;
if(j-1 >= 0)
dp[i] += dp[j-1];
}
}
if(s[i] == '>')
{
int j = i-1-dp[i-1];
if(j >= 0 && s[j] == '<')
{
dp[i] = dp[i-1] + 2;
if(j-1 >= 0)
dp[i] += dp[j-1];
}
}
maxn=max(maxn,dp[i]);
}
return maxn;
}
int main()
{
scanf("%s", s);
printf("%d\n", solve1());
return 0;
}
破解X星人的密文
思路:直接按题意模拟
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll sca()
{
ll su=0,f=1;
char c=getchar();
while(!isdigit(c))
{
if(c=='-')
f=-1;
c=getchar();
}
while(isdigit(c))
su=su*10+c-'0',c=getchar();
return su*f;
}
double a[100005];
int main()
{
int n;
while(~scanf("%d",&n))
{
getchar();
char s[1002];
gets(s);
int ls=strlen(s)/n;
for(int i=1;i<=ls;++i)
{
for(int j=1;j<=n;++j)
putchar(s[i*n-j]);
}
for(int i=strlen(s)-1;i>=ls*n;--i)
putchar(s[i]);
putchar('\n');
}
}
斐波那契三角形
思路:简单模拟,注意数据范围就行
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll sca(){
ll su=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c))su=su*10+c-'0',c=getchar();
return su*f;
}
int main()
{
int n;
ll a[81];
a[1]=1,a[2]=1;
for(int i=3;i<=80;++i)
a[i]=a[i-1]+a[i-2];
scanf("%d",&n);
if(n==1)
{
puts("1");
return 0;
}
if(n==2)
{
printf("1\n1 1 1\n");
}
printf("1\n1 1 1\n");
for(int i=3;i<=n;++i)
{
printf("1");
for(int j=2;j<=i;++j)
printf(" %d",a[j]);
for(int j=i-1;j>=1;--j)
printf(" %d",a[j]);
putchar('\n');
}
}
简单的数数
思路:直接模拟,正数直接统计二进制1的个数,负数先转正数,再取反,负数的补码=反码+1,反码+1注意要进位
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n>=0)
{
int ans=0;
while(n)
{
if(n%2)
++ans;
n/=2;
}
printf("%d\n",ans);
}
else
{
int ans=0,a[33]={0},cn=0;
n=abs(n);
while(n)
{
a[++cn]=n%2;
n/=2;
}
for(int i=1;i<=32;++i)
if(a[i])a[i]=0;
else a[i]=1;
a[1]+=1;
int l=1;
while(a[l]==2)//反码进位
a[l]=0,a[l+1]+=1,l++;
for(int i=1;i<=32;++i)
if(a[i])
++ans;
printf("%d\n",ans);
}
}
}
陷阱迷宫
思路:优先队列版bfs,定义优先队列按时间由小到大排序,每次时间最短的先遍历
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
char e[105][105];
int n,k;
int vi[105][105];
int d[4][2]= {1,0,0,1,-1,0,0,-1};
struct node
{
int x,y,ti;
bool operator<(const node &p)const
{
return ti>p.ti;//定义优先队列按时间逆序排列
}
};
int ans=0;
void bfs()
{
priority_queue<node> q;
q.push({1,1,0});
while(!q.empty())
{
node no=q.top();
q.pop();
if(no.x==n&&no.y==n)
{
//printf("%d\n",c);
ans=no.ti;
break;
}
if(vi[no.x][no.y])
continue;
vi[no.x][no.y]=1;
for(int i=0; i<4; i++)
{
int xx=no.x+d[i][0];
int yy=no.y+d[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&!vi[xx][yy]&&e[xx][yy]!='1')
{
if(e[xx][yy]=='#')
q.push({xx,yy,no.ti+k+1});
else
q.push({xx,yy,no.ti+1});
}
}
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; ++j)
scanf(" %c",&e[i][j]);
bfs();
if(!ans)
printf("No solution\n");
else
printf("%d\n",ans);
return 0;
}