一.水题(双指针)
题意:给一n个数:a1,a2,a3,...,an 同时进行判断两头数是否相等若相等则删除数ai,即前q个数若是等于后w个数就删除这(q+w)个数。
利用双指针进行遍历(ps:我是真的菜)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#define Ios ios::sync_with_stdio(0);cin.tie();cout.tie();
#define INF 0x3f3f3f
#define mod 1000000009
using namespace std;
typedef long long ll;
const int N=2e5+9;
int a[N];
int main()
{
Ios
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
ll sum=0;
ll ans=0;
for(int i=1,j=n;i<=j;)
{
if(sum>0){sum-=a[j];j--;}
else {
sum+=a[i];i++;
}
if(sum==0){ans=i+n-j-1;}
}
printf("%d\n",ans);
}
return 0;
}
//一个while也可以
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#define Ios ios::sync_with_stdio(0);cin.tie();cout.tie();
#define INF 0x3f3f3f
#define mod 1000000009
using namespace std;
typedef long long ll;
const int N=2e5+9;
int a[N];
void slove()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int ans=0;
int sum1=a[1];int sum2=a[n];
int l=1;int r=n;
while(l<r)
{
if(sum1==sum2)
{
ans=max(ans,n-r+1+l);
}
if(sum1<=sum2)
{
sum1+=a[++l];
}
if(sum1>sum2){
sum2+=a[--r];
}
}cout<<ans<<endl;
}
int main()
{
Ios
int T;
cin>>T;
while(T--)
{
slove();
}
return 0;
}
二.兔子(思维)
题意:
在一个长度为n的迷宫中有一个兔子,兔子每次可以往左或者往右跑,每次你可以检查某一个洞里是否有兔子。请问在最坏情况下,最少需要多少次必定能够找到这只兔子。
分析:
比较抽象的一道题,显然我们需要从某一方向一个一个找过去。但是可能存在一种情况,我们在i位置,兔子在i + 1位置,此时我们检查完i下一步去i + 1检查,此时兔子就跑到i位置去了,也就是错过。显然我们在最坏的情况下一定会错过。什么时候会错过呢?也就是我们和兔子的距离为奇数的时候,也就是我们所在位置的奇偶和兔子是相反的时候,我们就会错过这只兔子。加入我们从1开始找到n发现都没有兔子,就可以判断出我们和兔子的奇偶性相反,我们只需要在任何一个位置随便检查一次,这样奇偶性就和兔子相同,再从n找一遍兔子,这样一定能够找到。
但是这样的次数是2n + 1,能不能再少一点呢?我们发现,既然我们可以默认第一次和兔子的奇偶性一定相反,那我们干脆放弃第一格。我们从第二格子开始检查,检查到n-1格,如果和兔子的奇偶性相同,兔子一定会被逼到n - 1的位置。因此我们也不需要在n处检查。
我们在n - 1处再检查一次,这样就保证了和兔子的奇偶性相同,接下来顺次检查回第二个格子即可。(摘抄大佬题解🙏🙏)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#define Ios ios::sync_with_stdio(0);cin.tie();cout.tie();
#define INF 0x3f3f3f
#define mod 1000000009
using namespace std;
typedef long long ll;
const int N=2e5+9;
int main()
{
Ios
int n;
cin>>n;
if(n==1){printf("1\n1");}
else if(n==2)
{
printf("2\n2 2");
}else{
cout<<2*(n-2)<<endl;
for(int i=2;i<=n-1;i++) cout<<i<<" ";
for(int i=n-1;i>=2;i--) cout<<i<<" ";
}
return 0;
}
三.思维(dp?)
题意:给一个容量n,接下来给9个数: a1,a2,...,a9刚开始x为0.然后在9个数中选择ai,每选择一次n要减去ai,此时x变为x*10+i,然后再次进行选择直到n不能选为止,即n要小与a中最小的数。最后要达到x的值最大。
分析:刚开时觉得跟dp有关(我还是个dp菜鸟),但实际就是个思维题。。。。。首先要想x最大肯定是先让x的位数最大,就是选数的次数最多(每选一次数,x的位数加一)然后在次数最多的前提下,选择使x最大的值就行。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<map>
#include<queue>
#define Ios ios::sync_with_stdio(0);cin.tie();cout.tie();
#define INF 0x3f3f3f
#define mod 1000000009
using namespace std;
typedef long long ll;
const int N=2e7+9;
int a[N];
int ans[N];
int main()
{
Ios
int n;
cin>>n;
int minn=10000000;
int m=0;
for(int i=1;i<=9;i++)
{
cin>>a[i];
minn=min(minn,a[i]);
}
int q=n/minn;
for(int i=1;i<=q;i++)
{
for(int j=9;j>=1;j--)
{
if((n-a[j])>=(q-i)*minn)//注意判断条件n的范围
{
printf("%d",j);
n-=a[j];
break;
}
}
}
return 0;
}
四.D - Cutting Woods(set容器+二分)
题意:一根长为L米的木头,进行Q次操作,每次操作分为两类:操作一:输入x在x处砍断。操作二:输入x,判断x米处所在的木头有几米,输出长度。(被砍断的地方不会输入)
分析:首先我们得知道set容器的用法,在set容器中元素不会重复并且是有序的。在set中有自带的二分函数,注意返回的是地址。那我们只需要把砍断的地方插入到set中,输入x后,再根据二分函数去查找大于x的数,再减去容器中x前面的数后,就是x所在木头的长度。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#define Ios ios::sync_with_stdio(0);cin.tie();cout.tie();
#define INF 0x3f3f3f
#define mod 1000000009
using namespace std;
typedef long long ll;
int main()
{
Ios
set<int>s;
ll l;ll m;
cin>>l>>m;
s.insert(0);s.insert(l);
while(m--)
{
int x,y;cin>>x>>y;
if(x==1)
{
s.insert(y);
}else{
auto t=s.upper_bound(y);
cout<<*t-(*--t)<<endl;
}
}
return 0;
}