解析:把式子的x分出来,就是x*(2^0+2^1......+2^k-1)=n。所以先累加括号里的值打个表,只要n能整除它就输出
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+20;
ll a[maxn];
int main()
{
ll n;
int t;
cin>>t;
a[1]=1;
ll sum = 1;
for(int i=2;i<=1e9;i++)
{
sum*=2;
a[i]=a[i-1]+sum;
if(a[i]>=1e9)
break;
}
while(t--)
{
cin>>n;
for(int i=2;;i++)
{
if(n%a[i]==0)
{
cout<<n/a[i]<<endl;break;
}
}
}
}
题意:给出数组偶数长度n,能否输出一个:左边一半为偶数,右边一半为奇数,两边和相等。而且不存在重复数字。
解析:n/2的结果如果不是偶数,那么就肯定构造不出。比如6/2=3,奇数个奇数相加是奇数,是没办法等于偶数部分的和的。偶数部分直接按2,6,10构造,之间的差距不能为2,奇数部分直接参考左边对应位置,每次+1,-1即可,偶数差>2保证了奇数不会出现相等。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=2e5+20;
ll a[maxn];
ll b[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int md=n/2;
if(md%2!=0)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
ll k=2,tot=0;
ll sum=0;
for(int i=1;i<=md;i++)
{
sum+=k;
b[i]=k;
k+=4;
}
int ok=0;
for(int i=md+1;i<=n;i++)
{
if(!ok)
{
b[i]=b[i-md]-1;
ok=1;
}
else
{
b[i]=b[i-md]+1;
ok=0;
}
}
for(int i=1;i<n;i++)
cout<<b[i]<<" ";
cout<<b[n]<<endl;
}
}
}
题意:给出一组数,找出最长的正负交替的子序列(这里是通过删除某些数而得到的子序列),输出它们的最大和。
解析:找每一段连续正或负的最大值,累加即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f3f;
ll a[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
ll maxx=0;
ll sum=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(a[i]>0)
{
maxx=max(maxx,a[i]);
}
else
{
sum+=maxx;
maxx=0;
}
}
ll maxx2=-inf;
for(int i=0;i<n;i++)
{
if(a[i]<0)
{
maxx2=max(maxx2,a[i]);
}
else
{
if(maxx2!=-inf)
{
sum+=maxx2;
}
maxx2=-inf;
}
}
if(a[n-1]>0) //少加的情况。
sum+=maxx;
else
sum+=maxx2;
cout<<sum<<endl;
}
return 0;
}
题意:给出偶数n个大小在[1,k]之间的数,操作是把任意一个数变成[1,k]之间的任意值。要达到每个ai+an-i+1都为定值x,求最少操作数。
解析:我刚开始想的是,记录x出现的最大次数maxx,输出n-maxx,调了半天。原来我忽略了,ai和an-i+1,并不是随便改一个值就能使和达到[2,k]的任意值的。所以去分析每个x所对应的修改次数,下面开始讨论:
sum=a[i]+a[n-i+1],maxx=max(a[i],a[n-i+1]),minn=min(a[i],a[n-i+1])
1.如果x范围位于[2,minn],就算把maxx改成1,它们的和也是大于这个范围的,所以需要改动两次。
2.如果x范围位于[minn+1,maxx+k],关于这个区间我解释一下:minn+1是把maxx变成1所得的和,maxx+k是把minn变成k所得的和,这是只改一个数所对应的和的范围。
3.除了上面两种,就剩下[maxx+k+1,2*k]了。它和第一种一样,就算把minn变成k,它们的和也是小于这个范围的,所以要修改两个值。
以上就需要差分数组维护了,关于差分数组,我有一篇博客可对[L,R]每个数+1,就需要差分数组d[L]++,d[R+1]--。
较为啰嗦的更新代码:
for(int i=1;i<=n/2;i++)
{
ll sum=a[i]+a[n-i+1];
ll minn=min(a[i],a[n-i+1]);
ll maxx=max(a[i],a[n-i+1]);
d[2]+=2;
d[minn+1]-=2;
d[minn+1]++;
d[maxx+k+1]--;
d[maxx+k+1]+=2;
d[2*k+1]-=2;
d[sum]--;
d[sum+1]++; //本来和就等于sum,所以不需要更新,需要--。
}
完整代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<queue>
typedef long long ll;
using namespace std;
const int maxn=2e5+10;
ll a[maxn],d[2*maxn]; //差分数组开两倍
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n , k;
scanf("%d%d",&n,&k);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n/2;i++)
{
ll sum=a[i]+a[n-i+1];
ll minn=min(a[i],a[n-i+1]);
ll maxx=max(a[i],a[n-i+1]);
d[2]+=2;
d[minn+1]-=2;
d[minn+1]++;
d[maxx+k+1]--;
d[maxx+k+1]+=2;
d[2*k+1]-=2;
d[sum]--;
d[sum+1]++;
}
ll minn=d[2];
for(int i=3;i<=2*k;i++) //x范围就是[2,2*k]看看哪一个x所需要的更新次数最少?
{
d[i]+=d[i-1];
minn=min(d[i],minn);
}
cout<<minn<<endl;
}
}