热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

牛客算法入门竞赛笔记1

2021-10-20:昨天开的新坑,看了前几集感觉还可以,后悔为什么没早点跟着学,以前就感觉到了自己的知识体系太散了,这个课好像是11月还是12月结束,她说能达到icpc铜牌水平,

2021-10-20:昨天开的新坑,看了前几集感觉还可以,后悔为什么没早点跟着学,以前就感觉到了自己的知识体系太散了,这个课好像是11月还是12月结束,她说能达到icpc铜牌水平,我姑且相信好吧,希望跟着学完能有点进步,不求铜牌,cf先能上个1500吧呜呜呜。

# 模拟,枚举与贪心

字符串 (nowcoder.com)

 

尺取法(说实话这可能是我第一次见到这个做法,或者第一次知道它的学名),正常暴力想法应该是枚举两个端点,但是这里的右端点其实不用后退,想一下就知道了,因此只要两个端点差速右移就是O(n)的复杂度了

 #include
 using namespace std;
 int main(){
  mapx;
  string a;
  cin>>a;
  int l=0,r=0;
  for(int i=0;i1){
  x[a[i]]--;
  i++;
  }
  if(x.size()==26){
  ans=min(ans,r-i+1);
  }
  if(r==a.size()-1){
  break;
  }
  }
  cout<  return 0;
 }

丢手绢 (nowcoder.com)

尺取+1,但是我第一发wa了,90分,因为每一次移动要考虑的不仅是逆时针的最大值,还有顺时针的最大值。

 #include
 using namespace std;
 #define ll long long
 ll x[100001];
 int main(){
  int n;
  cin>>n;
  ll sum=0;
  for(int i=0;i  cin>>x[i];
  sum+=x[i];
  }
  ll l=0,r=0;
  ll now=0,ans=0;
  while(1){
  while(now*2<=sum&&r<=n-1){
  ans=max(now,ans);
  now+=x[r];
  r++;
  }
  while(now*2>sum){
  ans=max(ans,sum-now);//第一发没加这一句
  now-=x[l];
  l++;
  }
  if(r==n){
  break;
  }
  }
  cout<

Flip Game (nowcoder.com)

黑白棋问题:

1-每个棋子最多只能翻一次

2-我们枚举第一行的翻法(16种),然后递推出第二第三行的翻法(上一行哪个没翻第二行就翻下面那个),如果第四行都翻过来了,就成功,否则失败

题解里有个位运算的做法贼牛逼,把每一行都看成二进制串,假设我按第一个和第三个,那么对应的按操作的二进制码就是1010,现在我一共要对三个地方取反,第一:本位取反,直接让原码和操作码异或,第二:每个按操作的左边取反,操作码左移一位再异或,第三:每个按操作的右边取反,操作码右移一位再异或。

异或就是不进位的二进制加(好记)

看课程里老师调了半天,而我一眼就看出她那里有问题,给我急得()

 #include
 #include
 #define INF 0x3f3f3f3f
 using namespace std;
 ​
 int a[5],b[5];
 int ans=INF;
 ​
 int count_1_num(int x){
  int num=0;
  while(x>=1){
  num+=x%2;
  x/=2;
  }
  return num;
 }
 ​
 int fun(int*x){
  int t[5];
     //枚举16种第一行的情况
  for(int i=0;i<16;i++){
         //计算有几个1,就代表翻转了几次
  int num=count_1_num(i);
  for(int i=0;i<4;i++){
  t[i]=x[i];
  }
  t[0]=(t[0]^(i)^(i<<1)^(i>>1));
  t[1]=(t[1]^(i));
  t[0]=(t[0]&15);
  for(int k=1;k<4;k++){
  num+=count_1_num(t[k-1]);
  t[k]=(t[k]^(t[k-1])^(t[k-1]<<1)^(t[k-1]>>1));
  t[k+1]=(t[k+1]^(t[k-1]));
  //把有可能溢出的第五位变成0(这步是我没想到的)
  t[k]=t[k]&15;
  }
  if(t[3]==0){
  ans=min(num,ans);
  }
  }
 }
 ​
 int main(){
  for(int i=0;i<4;i++){
  for(int k=0;k<4;k++){
  char c;
  scanf(" %c",&c);
  if(c=='b'){
  //把a[i]的第k+1位变成1
  a[i]=a[i] | (1<  }else{
  b[i]=b[i] | (1<  }
  }
  }
  fun(a);
  fun(b);
     //第一发忘了加impossible居然0分是我没想到的,难道说。。。
  if(ans==INF){
  cout<<"Impossible"<  return 0;
  }
  cout<



 

 

震惊我一整年的做法,原题数据范围很小,可以把所有学号相加减去来的,但是如果数据范围非常大,学号之和已经超过long long了,就不能这样做了

于是,它来了,位运算:加减相消的原理和两次异或不变的原理是互通的,所以我们可以把所有的学号异或起来,然后再异或掉来的人的学号,剩下的就是没来的。

艹,太帅了,我直接拜发明这个算法的人为师,orz

再升级一下,如果两个人没来呢?

先和上面一样操作一遍得到两个没来的人的学号异或值,找到一位为1的,表明这两个人在这一位上不同,就可以将原数分为两块,每一块都是一个人没来的问题。

ohhhhhh,130没白花,长见识了。

Problem - 333E - Codeforces

 

这题听他讲好像没什么,一搜2500,妈耶,我到底在学什么,我一个1300分的人也配想2500的题?

思路很巧妙,我们枚举两两点之间的距离,将其从大到小排序,从长边到短边,构成的第一个三角形的最短边长的一半就是答案

但是。我们怎么判断什么时候构成一个三角形呢,最质朴的想法就是我每走过一条边都记录下每个点对应的已经检验过的邻点,如果出现一条边AC,A已经走过B,C也已经走过B,就成了,但是如果正常记录遍历的话必定会超时,怎么办呢? 震惊我两整年的想法来了,c++里有一个bitset类,就是一个很长的二进制串,我们存走过的点时,给它转化成对应的bitset位的值,然后每条新边来的时候判断一下两个端点的bitset的位与,如果不为零,就说明他们之前经过过同一个点,齐活!

我居然自己写出来了,艹,牛逼,去补一下bitset的接口(零碎点那个文档里)

#include
 using namespace std;
 pairx[3001];
 struct node{
  int x,y;
  double dis;
 };
 node t[10000001];
 bitset<3001>ans[3001];
 ​
 double distance(pairx,pairy){
  return sqrt((x.first-y.first)*(x.first-y.first)+(x.second-y.second)*(x.second-y.second));
 }
 ​
 bool com(node a,node b){
  return a.dis>b.dis;
 }
 ​
 ​
 int main(){
  int n;
  cin>>n;
  ans[0].reset();
  for(int i=1;i<=n;i++){
  cin>>x[i].first>>x[i].second;
  ans[i].reset();
  }
  int num=0;
  for(int i=1;i<=n;i++){
  for(int j=i+1;j<=n;j++){
  t[num].x=i;
  t[num].y=j;
  t[num].dis=distance(x[i],x[j]);
  num++;
  }
  }
  sort(t,t+num,com);
  for(int i=0;i  int x=t[i].x;
  int y=t[i].y;
  if((ans[x]&ans[y])!=0){
  printf("%.8lf",t[i].dis/2);
  break;
  }
  ans[x].set(y,1);
  ans[y].set(x,1);
 
  }
  return 0;
 }

月月查华华的手机 (nowcoder.com)

题意:判断序列b是否为a的子序列(不连续)

这题我看到的时候居然想上kmp,艹,绝了,kmp是匹配连续子串,这个是不连续序列,其实就是双指针,但是,这题数据范围很大,所以如过对每个目标串都用一次双指针,就t了。

因此这里用了一个预处理,记录下每个位置,其后面每个字母第一次出现的位置,从后往前扫一遍就有了,感觉有点像ccpc网络赛的那个字符串dp的签到题(一模一样好伐)。

 #include
 using namespace std;
 ​
 int x[1000001][30];
 int last[30];
 ​
 int main(){
  string a;
  cin>>a;
  memset(last,-1,sizeof(last));
  for(int i=a.size()-1;i>=0;i--){
  for(int k=0;k<26;k++){
  x[i][k]=last[k];
  }
  last[a[i]-'a']=i;
  }
  int t;
  cin>>t;
  while(t--){
  string b;
  cin>>b;
  int pos=last[b[0]-'a'];
  int beg=pos;
  if(pos<0){
  cout<<"No"<  continue;
  }
  int flag=1;
  for(int i=1;i  pos=x[pos][b[i]-'a'];
  if(pos<0){
 // pos=x[beg][b[0]-'a'];//这里就是因为没想明白串和序列,想回退
 // beg=pos;
  if(pos<0){
  flag=0;
  cout<<"No"<  break;
  }
  //i=0;
  }
  }
  if(flag==1){
  cout<<"Yes"<  }
  }
  return 0;
 }

Problem - 484A - Codeforces

题意:找l-r内二进制1数量最多的数

位运算+贪心,因为数据范围太大,必不可能遍历,所以考虑贪心,把左右边界都变为二进制,把左边界为0的二进制位一个个改成1,看是否还小于右边界即可。tql,我自己想绝对想不出来,但是实现是我自己写的,我也算是稍微了解一些位运算了吧(

 #include
 using namespace std;
 #define ll long long
 int main(){
  int t;
  cin>>t;
  while(t--){
  ll l,r;
  cin>>l>>r;
  ll ans=l;
  for(ll i=1;i<=r;i<<=1){
  if((l&i)==0){
  ans+=i;
  if(ans>r){
  ans-=i;
  break;
  }
  }
  }
  cout<

兔子的区间密码 (nowcoder.com)

题意:求l-r内两个数的异或的最大值

找到l,r的第一个不一样的二进制位,从这位开始后面可以保证一个数全是1,另一个全是0.

 #include
 using namespace std;
 #define ll long long
 int main(){
  int t;
  scanf("%d",&t);
  while(t--){
  ll a,b;
  scanf("%lld %lld",&a,&b);
  int i=63;
  for(;i>=0;i--){
  if((a>>i)!=(b>>i)){
  break;
  }
  }
  printf("%lld\n",(1LL<  }
  return 0;
 }

位运算:一位一位去考虑


递归与分治

表达式计算4 (nowcoder.com)

题意就跟标题一样,计算表达式,当时正好数据结构也布置了一个类似的作业,思路是每一次都找到运算级最低的那个符号,将表达式分为两个部分,分别计算。

 #include
 using namespace std;
 string a;
 //string转int
 int num(int l,int r){
  int ans=0;
  for(int i=l;i<=r;i++){
  ans*=10;
  ans+=a[i]-'0';
  }
  return ans;
 }
 //计算l到r的计算式
 int calc(int l,int r){
  int pos1=-1,pos2=-1,pos3=-1;
  int cnt=0;
  //找到不在括号里的优先级最低的运算符的位置
  for(int i=l;i<=r;i++){
  if(a[i]=='('){
  cnt++;
  }
  if(a[i]==')'){
  cnt--;
  }
  if(cnt==0){
  if(a[i]=='+'||a[i]=='-'){
  pos1=i;
  }
  if(a[i]=='*'||a[i]=='/'){
  pos2=i;
  }
  if(a[i]=='^'){
  pos3=i;
  }
  }
  }
  //如果没找到运算符
  if(pos1==-1&&pos2==-1&&pos3==-1){
  //要么是被括号整体括起来了
  //注:后面两个else if是为了排除多余的括号
  if(cnt==0&&a[l]=='('){
  return calc(l+1,r-1);
  }else if(cnt<0&&a[l]=='('){
  return calc(l,r-1);
  }else if(cnt>0&&a[r]==')'){
  return calc(l+1,r);
  }
  //要么是就是一个数字
  return num(l,r);
  }
  //+ -优先级最低,先判断
  if(pos1!=-1){
  if(a[pos1]=='+'){
  return calc(l,pos1-1)+calc(pos1+1,r);
  }else{
  return calc(l,pos1-1)-calc(pos1+1,r);
  }
  }
  //然后是* /
  if(pos2!=-1){
  if(a[pos2]=='*'){
  return calc(l,pos2-1)*calc(pos2+1,r);
  }else{
  return calc(l,pos2-1)/calc(pos2+1,r);
  }
  }
  //最后是乘方
  if(pos3!=-1){
  return pow(calc(l,pos3-1),calc(pos3+1,r));
  }
 }
 ​
 int main(){
  cin>>a;
  cout<  return 0;
 }

1027-kotori和糖果_2021秋季算法入门班第二章习题:递归、分治 (nowcoder.com)

题意:共n堆糖果,一堆一个,合并两堆数量不一样的花费1,求最少总花费

这题本来是个很简单的记忆化搜索,但是我没想清楚应该返回什么,我本来想着返回两端的长度,但是后来转念一想,不对啊,有了n两端长度不是都有了吗,所以应该返回的是形成这两端需要的操作数。

#include
using namespace std;
typedef long long ll;
map mp;
ll getans(ll n){
if(n==0) return 0;
if(mp.count(n)) return mp[n];
if(n&1){
mp[n]=2*getans(n/2);
}else{
mp[n]=getans(n/2)+getans(n/2-1)+1;
}
return mp[n];
}
int main(){
ll t;
scanf("%lld",&t);
while(t--){
ll n;
scanf("%lld",&n);
if(n==0)puts("0");
else printf("%lld\n",getans(n-1));
}
}


二分、三分、01分数规划

艹,我记得我写完这一部分的了,但是好像关电脑前忘了保存,然后就没了,心态爆炸,再写一遍,呜呜呜

小咪买东西 (nowcoder.com)

01分数规划经典题目,题意:给n个物品,每一个物品都有一个价值和花费,求买k个的最大总价值(val)和总花费之比(cos)

思路:我们假设这个最大比值是x,那么比x小的比值一定也存在这样的方案,比x大的比值一定不存在这样的方案,那么我们就可以考虑二分,对于一个比值num来说,如果可行,一定存在一个方案使得val/cos>=num-->val-numcos>=0;因此我们在判断的时候把所有val-numcost最大的k个值算在内,如果这样都不行那就是真的不行。

#include
using namespace std;
#define ll long long
struct node{
ll c,v,mar;
};
ll n,m;
node x[10001];
bool com(node a,node b){
return a.mar>b.mar;
}
bool fun(ll a){
ll num=0;
for(ll i=0;i x[i].mar=x[i].v-a*x[i].c;
}
sort(x,x+n,com);
ll sum=0;
for(ll i=0;i sum+=x[i].mar;
}
if(sum<0){
return false;
}else{
return true;
}
}
int main(){
ll t;
cin>>t;
while(t--){
cin>>n>>m;
for(ll i=0;i cin>>x[i].c>>x[i].v;
}
ll l=0,r=1e8+1;
ll mid=0;
while(l mid=(l+r+1)/2;
if(fun(mid)){
l=mid;
}else{
r=mid-1;
}
}
cout< }
return 0;
}

gpa (nowcoder.com)

和上一题差不多,就是把最大值公式变了一下,我们一样做

#include
using namespace std;
#define INF 0x3f3f3f3f
#define ll double
struct node{
double a,b,tem;
};
node x[100001];
int n,m;
bool com(node a,node b){
return a.tem}
bool fun(ll a){
for(int i=0;i x[i].tem=x[i].a*(x[i].b-a);
}
sort(x,x+n,com);
for(int i=0;i if(x[i].tem<0){
x[i].tem=-INF;
}
}
ll sum=0;
for(int i=0;i if(x[i].tem==-INF){
continue;
}
sum+=x[i].tem;
}
if(sum<0){
return false;
}else{
return true;
}
}
int main(){
cin>>n>>m;
for(int i=0;i cin>>x[i].a;
}
for(int i=0;i cin>>x[i].b;
}
double l=0,r=1e11+1;
while(r-l>1e-6){//这里答案是小数,所以我们用控制精度的方法
double mid=(l+r)/2;
if(fun(mid)){
l=mid;
}else{
r=mid;
}
}
printf("%.6lf\n",l);
return 0;
}


堆栈、队列、单调栈、单调队列

[NOIP2016]蚯蚓 (nowcoder.com)

题意:给你n个数,每次会将一个数分割成比例为定值的两个数,求m次分割怎么让每个数尽可能小,每个数还会随时间增长一定值。

这题本来觉得没啥难的,优先队列嘛,谁不会啊(),但是看了眼数据范围,完蛋,会t,没办法,只能听雨巨讲了。

思路真的很巧妙,假设我们将最初的序列排序,拆分之后将两段分别放进两个队列里面,因为我们每次拆分的一定都比上一次小(或者一样)因此拆分后的两段一定也比先前的两段小,所以我们后放入队列的一定比先放入的小,这样就保证了有序,每次选择最大的时候只要去找三个队列的头即可。tql,未曾设想的道路。

但是这个输出要求就很恶心,我好不容易写完,你非要在输出上折磨我是什么意思

#include
#include
#include
using namespace std;
#define ll long long
int main() {
queueq[3];
int x[100001];
ll n, m, Q, u, v, t;
cin >> n >> m >> Q >> u >> v >> t;
double p = (double)u / v;
for (int i = 0; i cin >> x[i];
}
sort(x, x + n, greater());
for (int i = 0; i q[0].push(x[i]);
}
int now = 0;
while (now int mn = -0x3f3f3f3f, maxindex=-1;
for (int i = 0; i <3; i++) {
if (!q[i].empty() && q[i].front() > mn) {
mn = q[i].front();
maxindex = i;
}
}
if (maxindex==-1) {
break;
}
mn += now * Q;
q[maxindex].pop();
q[1].push((int)(u * mn/v) - now * Q-Q);
q[2].push(mn - (int)(u * mn/v) - now * Q-Q);

if ((now+1) % t == 0) {
cout < }
now++;
}
cout < now=1;
while (!q[0].empty() || !q[1].empty() || !q[2].empty()) {
int mn = -0x3f3f3f3f, maxindex=-1;
for (int i = 0; i <3; i++) {
if (!q[i].empty() && q[i].front() > mn) {
mn = q[i].front();
maxindex = i;
}
}
if (maxindex==-1) {
break;
}
if(now%t==0){
cout < }
now++;
q[maxindex].pop();
}
return 0;
}

Sliding Window (nowcoder.com)

 

动态维护一个在i-k~i之间可能成为答案的队列。

以最大值为例,如果后一个比前一个大,那么前一个就失去了成为答案的机会,就可以出队了,反之就不出队,但是当这个值的位置比区间的左端点还小的时候也要出队,本来我想用队列存数据的,但是雨巨点醒了我,存数据的话还要直到下标,所以我们直接把下标存起来,到原数组里找对应的数据即可。

第一次用对拍,有点爽,第一次交的时候wa在了长度为1的时候。

#include
using namespace std;
int x[1000011];
int main(){
// freopen("a.in","r",stdin);
// freopen("std.out","w",stdout);
int n,k;
cin>>n>>k;
for(int i=0;i cin>>x[i];
}
if(n==1){
cout< return 0;
}
dequeq;
// q.push_back(0);第一次wa在这.以后别tm提前插入行不行,对拍的时候是很爽,但是写起来很麻烦
for(int i=0;i while(!q.empty()&&x[q.back()]>x[i]){
q.pop_back();
}
q.push_back(i);
if(q.front()<=i-k){
q.pop_front();
}
if(i+1>=k){
cout< }
}
cout< q.clear();
for(int i=0;i while(!q.empty()&&x[q.back()] q.pop_back();
}
q.push_back(i);
if(q.front()<=i-k){
q.pop_front();
}
if(i+1>=k){
cout< }
}
return 0;
}

Largest Rectangle in a Histogram (nowcoder.com)

单调栈的板子题,所谓单调栈就是我们维护一个单调的栈,每当有新数据进来时,如果它破坏了原有的单调性,我们就一直出栈直到单调为止。

题意:给你一串高度不等高的等宽柱子,求能够在里面划出的最大的矩形的面积。

思路:我们存下每个柱子往左能够延伸的最大长度,如果新加的柱子比之前的高,那它的最大宽度就是1,如果新加的柱子比之前的矮,那我们在出栈的过程中把每一个出栈的柱子的往左延伸的最大长度相加得到的就是这个新柱子的最大长度,当然,如果一个柱子出栈了,就说明它不可能再向右延申了,这时我们用高度×它能向左延申的最大长度就是一个可能的最大面积。

#include
using namespace std;
#define ll long long
int x[100001];
int num[100001];//记录每个柱子能够向左延伸的最大长度
int main(){
int n;
while(cin>>n&&n){
for(int i=1;i<=n;i++){
cin>>x[i];
}
stackstk;
ll ans=0;
x[++n]=0;
for(int i=1;i<=n+1;i++){
ll temp=0;
while(!stk.empty()&&x[i]<=x[stk.top()]){
temp+=num[stk.top()];
ans=max(ans,temp*x[stk.top()]);
stk.pop();
}
stk.push(i);
num[stk.top()]=temp+1;
}
cout< }
return 0;
}



推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
author-avatar
半夏✔
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有