目录
E. Binary Deque
题意是给你一个01的序列,让你可以删掉前面的一个数或者后面的一个数,让序列的总和恰好等于m(给定),问最少操作次数
这题一看就知道是双指针,我原来是把每个1的位置记录下来,看看最终的删的那个位置在哪,可惜了,双指针我不好捏,写了好长时间还是不太对。
用二分:把前缀和后缀分别算出来,然后枚举一下后缀,这样就知道前缀应该是多少了,最后求最少的操作次数,然后注意一下边界,因为后缀或者前缀是有可能一次也不操作的,那次数是0,所以那数也是0,边界是[0,n-1],然后还有最后求最少次数的那个,是枚举的位置,而不是数字(数字只是一段区间的和而已),我一开始弄混了QAQ
#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+10;
int f[N],b[N],a[N];
int main(){
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
memset(f,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
{
cin>>a[i];
f[i]=f[i-1]+a[i];
}
if(f[n]<m)
{
cout<<"-1"<<"\n";
continue;
}
int t=f[n]-m;
for(int i=n;i>=1;i--) b[i]=b[i+1]+a[i];
int res=0x3f3f3f3f;
for(int i=n+1;i>=0;i--)
{
int x=b[i];
int l=0,r=n+1;
while(l<r)
{
int mid=l+r>>1;
int y=t-x;
if(f[mid]>=y) r=mid;
else l=mid+1;
}
if(l>=i) continue;
if(f[l]+x==t) res=min(res,n-i+l+1);
}
cout<<res<<"\n";
}
return 0;
}
F. 3SUM
题意就是,能否选三个数相加使得最后末尾是3
无了个大语,原来写的可能没错,我忘记初始化了,然后就没然后了,没看出来,还以为是代码的问题...
思路就是末尾是3,只需要看每个数的末尾就行了,末尾的数相加取余10看看是不是3就行,然后肯定是0到9里面的数,避免111这种情况,所以个数要++,然后就暴力,有点回溯的思想,在减完之后,要继续搜,恢复一下现场,其他的没啥
#include<iostream>
#include<cstring>
using namespace std;
const int N=100;
int a[N];
int main(){
int T;
cin>>T;
while(T--)
{
int n;
scanf("%d",&n);
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
int yu=x%10;
a[yu]++;
}
int f=0;
for(int i=0;i<=9;i++)
{
if(a[i])
{
a[i]--;
for(int j=0;j<=9;j++)
{
if(a[j])
{
a[j]--;
for(int k=0;k<=9;k++)
{
if(a[k])
{
a[k]--;
if((i+j+k)%10==3)
f=1;
a[k]++;
}
}
a[j]++;
}
}
a[i]++;
}
}
if(f) cout<<"YES"<<"\n";
else cout<<"NO"<<"\n";
}
return 0;
}
G. 2^Sort
Problem - G - Codeforces
给你一个序列,每个数依次乘2的次方,按照区间来如果都能保证前一个数字<后一个数字,就符合条件++,最后问个数
我跟个呆子似的
明明数据范围那么大,我还在用pow,怎么那么死脑筋呢,嗯?,我自己都想到约分,后一个数的二倍比前一个数大就可以,还在pow...
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N];
int main(){
ll T;
cin>>T;
while(T--)
{
ll n,len;
scanf("%lld%lld",&n,&len);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
ll q=n-len;
ll num=0,k=1;
while(1)
{
ll f=1;
ll t=a[k],p=1;
for(ll i=k+1;i<=k+len;i++)
{
ll po=pow(2,p);
// cout<<a[i]*po<<endl;
if(a[i]*po<=t)
{
f=0;
break;
}
p++;
t=a[i]*po;
}
if(f) num++;
k++;
if(k>q) break;
}
cout<<num<<"\n";
}
return 0;
}
/*
原始的大小关系不会变,看看新的,如果比上一个要大就++
先判断一下原始的大小关系
*/
但是这个代码不是不可以改
这个样子:(超时了QAQ)应该能想到的...
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N];
int main(){
ll T;
cin>>T;
while(T--)
{
ll n,len;
scanf("%lld%lld",&n,&len);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
ll q=n-len;
ll num=0,k=1;
while(1)
{
ll f=1;
ll t=a[k];
for(ll i=k+1;i<=k+len;i++)
{
// cout<<a[i]*po<<endl;
if(a[i]*2<=t)
{
f=0;
break;
}
t=a[i];
}
if(f) num++;
k++;
if(k>q) break;
}
cout<<num<<"\n";
}
return 0;
}
/*
原始的大小关系不会变,看看新的,如果比上一个要大就++
先判断一下原始的大小关系
*/
下面是ac代码:符合条件的记为1,不符合记为0,最后看看连续的1有多少,可以构成多少个区间
(看了一位大佬的博客QAQ)
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],s[N];
int main(){
ll T;
cin>>T;
while(T--)
{
int n,k;
memset(s,0,sizeof(s));
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]*2>a[i-1]) s[i]=1;
else s[i]=0;
}
int t=0,sum=0;
for(int i=1;i<=n;i++)
{
if(s[i]) t++;
if(!s[i])
{
if(t>=k+1) sum+=(t-k);
t=1;
}
}
if(t>=k+1) sum+=(t-k);
cout<<sum<<"\n";
}
return 0;
}
不过这个思想好熟悉,多多回忆一下,总结总结