这是一个悲伤的夜晚,做题太慢了,导致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;
}