CF每日一練(2.8)
CF-1110
A. Parity
- 快速冪的思想,考慮最後一位即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll b,k; ll a[100010]; int main(){ scanf("%lld%lld",&b,&k); for(int i=0;i<k;i++) scanf("%lld",&a[i]); ll ans = 0; ll base = 1; for(int i=0;i<k;i++){ ans = (ans+a[k-i-1]*base)%10; base = base*b%10; } if(ans%2)puts("odd"); else puts("even"); return 0; }
可以再多想一想。
? \[n = a_1\cdot b^{k-1} + a_2\cdot b^{k-2} + \cdots + a_{k-1} \cdot b + a_k\]
- b為偶數時,n的奇偶性只與\(a_k\) 有關
- b為奇數時,\(b^k\) 為奇數,所有n的奇偶性只與 a 序列中奇數個數有關。
#include<bits/stdc++.h> using namespace std; int b,k,i,x,y; int main(){ for(cin>>b>>k;i<k;i++) cin>>x,y+=x%2; cout<<((b%2?y%2:x%2)?"odd":"even"); }
B. Tape
n == k 時直接輸出 n 就好
n <= k 時,一些點要合並,由於合並產生的操作可能會使一段上面有多個點,所以我們要先把 k 個點都用長度為 1 的去填好。之後合並的時候只需要考慮點與點之間的距離即可(YY一下,你就知道)
- 當 k 等於 n,則直接輸出 n
- 當 k 小於 n,則先把k段用長度為1補齊,再加上 (n-k) 段比較小的距離。
#include <bits/stdc++.h> using namespace std; int n,m,k; int a[100010]; int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=n-1;i>0;i--) a[i] = a[i]-a[i-1]; sort(a+1,a+n); int ans = k; for(int i=1;i<=(n-k);i++) ans += a[i]; cout<<ans<<endl; return 0; }
C. Meaningless Operations
根據 Note 可以得知只要湊出一個 0 ,就可能得到最大的gcd。
當 \(a\neq (2^x -1)\) , 則一定可以找到一個 b 使得
- $ a \oplus b = 2^x -1$ ,\(a \& b = 0\)
當 \(a = (2^x - 1)\) ,則可以發現
? \(gcd( a\oplus b, a\&b) = gcd(2^x-1-b,b) = gcd(2^x-1,b)\)
- 因為 \(gcd(x,x+y) = gcd(x,y)\)
- 所以只需要找到 a 的最大因數(非a) 即可。
復雜度\(O(q\sqrt m)\) 。但是可以打表做(也可以直接暴力求)
#include <bits/stdc++.h>
using namespace std;
int po[30];
int res[30] = {0,1,1,1,5,1,21,1,85,73,341,89,1365,1,5461,4681,21845,1,87381,1,349525,299593,1398101,178481,5592405,1082401,22369621};
void init(){
po[0] = 1;
for(int i=1;i<30;i++)
po[i] = po[i-1]*2;
}
bool check(int x){
for(int i=1;i<30;i++)
if(x==po[i]-1)
return true;
return false;
}
int calc(int x){
int num =0;
while(x)
{
x/=2;
num++;
}
return num;
}
int main(){
init();
int q;
cin>>q;
while(q--){
int n;
cin>>n;
if(check(n)){
int num = calc(n);
cout<<res[num]<<endl;
}
else{
for(int i=1;i<30;i++){
if(n>=po[i]&&n<po[i+1]){
cout<<po[i+1]-1<<endl;
break;
}
}
}
}
}
D. Jongmah
(好難的dp,其實早在 HDU-6188 就出現過了
首先這個題或許可以貪心,但是目前沒找到正確的貪心策略(幾乎都是dp
首先考慮什麽狀態(我不是自己想到的,但是知道這樣做之後慢慢琢磨確實應該這麽做
狀態需要轉移,那麽我們需要保留那些結果?
d[i][j][k]
:j 個 [i-1,i,i+1]
,k 個 [i,i+1,i+2]
時的最大組合數轉移:
d[i+1][k][l] = max( d[i+1][k][l], d[i][j][k] + l + (a[i+1]-j-k-l)/3) )
答案為
d[m+1][0][0]
,(總長度為m)
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[1000100];
int d[1000100][3][3];
int main(){
scanf("%d%d",&n,&m);
for(int i=0,x;i<n;i++){
scanf("%d",&x);
a[x]++;
}
int ans = 0;
d[0][0][0] = 0;
for(int i=0;i<=m;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
for(int l=0;l<3&&l+k+j<=a[i+1];l++)
d[i+1][k][l] = max(d[i+1][k][l],d[i][j][k]+l+(a[i+1]-j-k-l)/3);
cout<<d[m+1][0][0]<<endl;
return 0;
}
E. Magic Stones
考慮差分:\(d_i = c_{i+1} - c_i\)
交換前後:$ c_j -> c_j^{’} = c_{j+1} + c_{j-1} - c_j$
- \(d_{j-1}^{‘} = c_j^{‘} -c_{j-1} = c_{j+1} + c_{j-1} - c{j} - c_{j-1} = c_{j+1}-c_j = d_j\)
- \(d_j^{‘} = c_{j+1}-c_j^{‘} = c_{j+1} - (c_{j+1} + c_{j-1} -c_j) = c_j - c_{j-1} = d_{j-1}\)
只需比較 c 和 d 的差分序列是否相同即可。等等,你還需要註意一點,頭和尾是不能變化的
#include <bits/stdc++.h>
using namespace std;
int n;
int c[100010],d[100010];
multiset<int> s1,s2;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&c[i]);
if(i)s1.insert(c[i]-c[i-1]);
}
for(int i=0;i<n;i++){
scanf("%d",&d[i]);
if(i)s2.insert(d[i]-d[i-1]);
}
if(c[0]!=d[0]||c[n-1]!=d[n-1])puts("No");
else if(s1==s2)puts("Yes");
else puts("No");
return 0;
}
CF每日一練(2.8)