这是一个悲伤的夜晚,做题太慢了,导致d题甚至都没时间做了,早上起来发现C还被踩了。
题目大意:
给你一个n,还给你一个等式x + 2x + 4x + 8x + …+2^(k - 1)x = n,其中k(>1)
思路:
一个水题,因为题目保证答案有解,直接枚举k解这个一元方程即可。(一个水题写了20多分钟啊啊。。。还是做题太少)
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long int ll;
void solved(){
int t;cin>>t;
while(t--){
ll n;cin>>n;
ll cnt = 1;
for(int i = 1; i <= 100; i++){
cnt += (1<<i);
//cout<<cnt<<endl;
if(n % cnt == 0){
//cout<<n<<" "<<cnt<<endl;
cout<<(n / cnt)<<endl;break;
}
}
}
}
int main(){
solved();
return 0;
}
题意:
给你一个n(保证n是偶数),要你构造这样的一个序列,前面n/2个元素是偶数,后面n/2个是奇数,并且前面n/2和后面n/2个数之和相等,并且每个数是唯一的。
思路:
一个简单的构造,直接前面n/2个用公差为2的等差数列构造即可,首项为2,后面n/2 - 1个用首项为1公差为2的等差数列构造即可。要使得构造成功n/2得是一个偶数,这样两边的和才能均摊。那么我们可以知道n/2必定是一个偶数,因为后面n/2项和会少于前面n/2项,那么只需要用前面n/2项和减去后面n/2-1项和即可。显然第n项必定是一个奇数。
这个写复杂了,当时场上题意理解错了,我以为只有第一个n/2是偶数,第二个n是奇数就行了。。。所以后面改的代码思路有一点点乱。这个可以直接输出就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long int ll;
ll a[maxn];
void solved(){
int t;cin>>t;
while(t--){
ll n;cin>>n;
if(n == 2){
cout<<"NO"<<endl;continue;
}
bool flag = false;
if((n/2)%2==0)flag = true;
if(flag){
cout<<"YES"<<endl;
ll l = 2;
int pos = 1;
for(int i = 1; i <= n / 2; i++){
a[i] = l;
l += 2;
}
ll r = 1;
ll sum = 0;
for(int i = n/2+1;i <= n; i++){
a[i] = r;
sum += a[i];
r += 2;
}
sum -=a[n];
a[n] = (n/2)*(2+a[n/2])/2-sum;
for(int i = 1; i <= n; i++){
cout<<a[i]<<" ";
}
cout<<endl;
}else{
cout<<"NO"<<endl;
}
}
}
int main(){
solved();
return 0;
}
题目大意:
给你一个序列,要你在满足长度最大的情况下输出这个序列的最大值。就是说你要在一段连续的子序列选数,就是一个负数一个正数这样去选。
思路:
这个题很简单,O(n)暴力模拟一下就行了,大概几分钟就写完了。
早上起来发现被hack了,原因为while()里面还要满足i<=n(我真是个傻子)
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long int ll;
ll a[maxn];
void solved(){
int t;cin>>t;
while(t--){
int n;cin>>n;
for(int i = 1; i <= n; i++)cin>>a[i];
ll ans = 0;
vector<ll>ve;
for(int i = 1; i <= n;){
ll m = -1e18,M = -1e18;
bool f1 = false,f2 = false;
while(i <= n && a[i] > 0){
if(a[i] > M){
M = a[i];f1 = true;
}
i++;
}
while(i <= n && a[i] < 0){
if(a[i] > m){
m = a[i];f2 = true;
}
i++;
}
if(f1)
ve.push_back(M);
if(f2)
ve.push_back(m);
}
for(int i = 0; i < ve.size();i++){
ans += ve[i];
}
cout<<ans<<endl;
}
}
int main(){
solved();
return 0;
}
题目大意:
给你n个小于等于k的数,要你构造出一个ai + a(n - i + 1) = x这样的序列。你可以用[1,k]中的数去替换掉ai。
思路:
考虑每队ai和a(n- i + 1)替换掉其中一个可以得到的和,与替换掉2个可以得到的和。
替换掉其中一个我们可以得到他们的和的取值范围为[min(ai,a(n - i + 1))+ 1,max(ai,a(n - i + 1)) + k]。
替换掉两个我们可以得到他们和的取值范围为[2,min(ai,a(n - i + 1))]∪[max(ai,a(n - i + 1)) + k + 1, 2 * k]。
如果不用替换就是ai + a(n - i + 1)。我们令这个区间 -1.因为它不用替换嘛,但是我们替换1的时候给计算进去了,所以这里需要弄出来。
然后从[2, 2 * k]中选最小值,就是所有组为了得到这个数需要替换的最少次数。
因为这里需要用到区间加法,但是n=2e5,如果暴力O(n^2)会超时,所以这里我们需要用到差分数组,如果不懂的可以百度一下。或者树状数组线段树都行。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
typedef long long int ll;
ll a[maxn],s[maxn << 1];
void add(int l,int r,int v){
s[l]+=v;s[r+1]-=v;
}
void solved(){
int t;cin>>t;
while(t--){
int n,k;cin>>n>>k;
for(int i = 2; i <= 2 * k; i++)s[i] = 0;
for(int i = 1; i <= n ;i++)cin>>a[i];
for(int i = 1; i <= n/2 ;i++){
int x = a[i];
int y = a[n - i + 1];
if(x > y)swap(x,y);
add(x+y,x+y,-1);
add(x+1,y+k,1);
add(y+k+1,2*k,2);
add(2,x,2);
}
ll ans = 1e18;
for(int i = 2; i <= 2 * k ;i++){
s[i] += s[i - 1];ans = min(ans,s[i]);
}
cout<<ans<<endl;
}
}
int main(){
solved();
return 0;
}