這是一個悲傷的夜晚,做題太慢了,導致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;
}