Codeforces Round #696
Codeforces Round #696
文章目錄
- CF1474A Puzzle From the Future
- 題意:
- 題解:
- 代碼:
- CF1474B Different Divisors
- 題意:
- 題解:
- 代碼:
- CF1474C Array Destruction
- 題意:
- 題解:
- 代碼:
- CF1474D Cleaning
- 題意:
- 題解:
- 代碼:
- CF1474E What Is It?
- 題意:
- 題解:
- 代碼:
- CF1474F 1 2 3 4 ..
- 題意:
- 題解:
- 代碼:
CF1474A Puzzle From the Future
題意:
在2022年,Mike發現了兩個長度為n的二進制整數a和b(它們都只由前導有0的數字(和1)表示)。為了不忘記它們,他想用以下方式構造整數d:
他將a和b按位加和而不進行進位轉換,從而得到一個整數c,所以c可能有一個或多個2。例如,0110和1101按位求和的結果是1211,011000和011000按位加和的結果是022000;
之后,Mike將c中相等的連續數字折疊為1位,因此得到d。經過這個操作,1211變成121,022000變成020(所以,d不會有相等的連續數字)。
不幸的是,邁克在自己計算d之前就失去了整數a。現在,為了讓他高興起來,你要找到一個長度為n的二進制整數a,使d成為最大的可能的整數。
最大可能的整數的意思是102>21,012<101,021=21,以此類推。
題解:
規律題,找到規律就行
我們發現a的第一位肯定是1(從左往右數),為了讓d更大,我們要讓a加b更大,且不能存在一樣的數,所以從第二位開始,如果a和b的第i-1位 等于 b的第i位+1,說明第a位就不能取1,只能取0,反之可取1
代碼:
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } int main() {int t;cin>>t;while(t--){int n;cin>>n;string s;cin>>s;string b="1";for(int i=1;i<n;i++){int w=s[i]-'0';int x,y;x=s[i-1]-'0';y=b[i-1]-'0';if(w+1==x+y)b+='0';else b+='1';}cout<<b<<endl;}return 0; }CF1474B Different Divisors
題意:
求一個數,這個數至少有4個除數,且每個除數的差至少是d。
題解:
根據題意多舉例子就能發現:
第一位肯定是1,最后一位肯定是中間所有數的乘積,然后第二位比第1位大d,且我們要保證除了第一位和最后一位,其他位的數都必須是質數,這樣可以保證最后一位最小
所以我們每次找大于前一位+d的質數
代碼:
#include<bits/stdc++.h> typedef long long ll; using namespace std; inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } const int maxn=1e7+9; int tag[maxn],prime[maxn]; int cnt=0; void Prime(int N) {memset(tag,0,sizeof(tag));tag[0]=tag[1]=1;for(int i=2;i<N;i++){if(!tag[i])prime[cnt++]=i;for(int j=0;j<cnt&&prime[j]*i<N;j++){tag[i*prime[j]]=1;if(i%prime[j]==0)break;}} } int main() {Prime(1000000);int t;cin>>t;while(t--){int d;cin>>d;int x=1;x+=d;x=lower_bound(prime,prime+cnt,x)-prime;int y=prime[x];y+=d;y=lower_bound(prime,prime+cnt,y)-prime;cout<<prime[x]*prime[y]<<endl;} }CF1474C Array Destruction
題意:
題目給出一個長度為2n的正整數序列,現在問你是否存在一個x使得可以不斷的進行如下操作,直到這個序列變為空:
從序列中找到兩個數字a1,a2,使得a1+a2==x,然后從序列中刪掉這兩個數字,x的值也被更新,x=max(a1,a+2)。
題解:
因為n的范圍并不大,所以x可以暴力枚舉
因為x是單調遞增的,所以第一個x必然是最大的那個數加上另一個數,最大的數是確定的,另一個數可以枚舉
所以一開始枚舉2n-1個另一個數,和最大的那個數一起組成最初的x,然后接下來每一步都知道x是誰,且知道最大值是誰,那么x-最大值直接二分查找。一直進行下去,如果中間有二分找不到的數,就從頭枚舉另一個數重新來
復雜度:O(n2logn)
這題主要看你set用的熟不熟練了
代碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 2020; int T, n, a[maxn], ans; multiset<int> st; vector<pair<int, int> > vec;bool _check(int ii) {st.clear();for (int i = 0; i < 2*n-1; i ++) {if (i == ii) continue;st.insert(a[i]);}vec.clear();vec.push_back({a[2*n-1], a[ii]});ans = a[2*n-1] + a[ii];int tmp = a[2*n-1];for (int i = 1; i < n; i ++) {multiset<int>::iterator it = st.end(), it2;it --;int x = *it;st.erase(it);it2 = st.lower_bound(tmp - x);if (it2 == st.end()) return false;int y = *it2;if (x + y != tmp) return false;vec.push_back({x, y});tmp = max(x, y);st.erase(it2);}return true; }bool check() {for (int i = 0; i < 2*n-1; i ++) if (_check(i)) return true;return false; }int main() {scanf("%d", &T);while (T --) {scanf("%d", &n);for (int i = 0; i < 2*n; i ++) scanf("%d", a+i);sort(a, a+2*n);if (check()) {puts("YES");printf("%d\n", ans);for (auto x : vec) printf("%d %d\n", x.first, x.second);}else puts("NO");}return 0; }CF1474D Cleaning
題意:
每次拿走兩個相鄰位置的一個石頭(可以拿多次),且有且只有一次交換兩個相鄰位置的機會,問能不能將所有石頭拿走
題解:
如果有后一個數字大于前一個數字,我們從前往后就會出現后一個為0,前一個還不為0的情況,所以一定不可能。同理從后往前刪除是一樣的情況
我們用pre預先處理從前往后的差分
suf預處理從后往前的差分
如果pre與suf數組存在同一位置相等,說明就可以全部拿走
因為還有一次交換的機會,所以直接暴力交換i和i+1兩個位置,然后求出當前位置新的pre和和suf,用于判斷是否相等
代碼:
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> using namespace std ; const int maxn = 2e5 + 10 ; typedef long long ll ; ll a[maxn] , pre[maxn] , suf[maxn] ; const ll inf = 1e18 ;int main(){int t ;cin >> t ;while(t--){ll n ;cin >> n ;memset(pre , 0 , sizeof(pre)) ;memset(suf , 0 , sizeof(suf)) ;for(ll i = 1 ; i <= n ; i++) cin >> a[i] ;for(ll i = 1 ; i <= n ; i++){if(a[i] >= pre[i-1]) pre[i] = a[i] - pre[i-1] ;else pre[i] = inf / 2 ; // 預處理pre,當有不符合情況的時候,pre數組從此往后全為inf/2}for(ll i = n ; i >= 1 ; i--){if(a[i] >= suf[i+1]) suf[i] = a[i] - suf[i+1] ;else suf[i] = inf ;// 從后往前,如果有不符合,那么全為inf}bool flag = 1 ;for(ll i = 1 ; i <= n - 1 ; i++){if(pre[i] == suf[i+1]){ // 如果可以接上的話直接輸出yes就行flag = 0 ;break ;}else{ll tmp1 = a[i] ; // 如果接不上,那么交換a[i]與a[i+1] 然后實現pre[i] 和 suf[i+1] 如果接的上輸出yesll tmp2 = a[i+1] ;if(tmp1 >= suf[i+2] && tmp2 >= pre[i-1]){tmp1 -= suf[i+2] ;tmp2 -= pre[i-1] ;if(tmp1 == tmp2){flag = 0 ;break ;}}}}if(!flag) cout << "YES" << endl ;else cout << "NO" << endl ;}return 0 ; }CF1474E What Is It?
題意:
一個排列,你可以選擇i , j ( i ≠ j ) ,滿足a [ j ] = i , 然后交換a[i],a[j],交換收益為 (i-j)2。
讓你構造一個長度為n的排列,使得交換過程所得收益最大。
題解:
我們不難發現我們每次交換,都會使得至少一個數歸位(也就是a[i]=i),當所有位置歸位時我們將無法再交換,所以最多交換n-1次
我們再考慮距離為n-1的對數最多是多少?只有一對,就是(1,n),除此之外沒有了
我們再考慮n-2的對數最多是多少?最多是兩對,就是(1,n-1)和(2,n),(當然其他考慮也是一樣的),最多只有兩對
當距離為n-3的也只有兩對
那么最大收益就是(n-1)2 + 2*(n-2)2 + 2*(n-3)2+…
這樣收益就算出來了
至于步驟我們可以你想考慮,也就是一開始數組a都是歸位的,然后先弄(n-1)對,再弄(n-2)對,這樣就得到最后的排列和交換過程
代碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f; const int maxn = 2e5 + 7; int a[maxn]; int main() {int T;scanf("%d",&T);while(T--) {int n;scanf("%d",&n);for(int i = 1;i <= n;i++) {a[i] = i;}vector<pair<int,int> >vec;ll ans = 0;int cnt = n - 1;for(int i = n - 1;;i--) { //交換兩點的距離swap(a[i + 1],a[1]);vec.push_back({i + 1,1});ans += 1ll * i * i;cnt--;if(cnt == 0) break;if(i == n - 1) continue;swap(a[n - i],a[n]);vec.push_back({n - i,n});ans += 1ll * i * i;cnt--;if(cnt == 0) break;}printf("%lld\n",ans);for(int i = 1;i <= n;i++) {printf("%d ",a[i]);}printf("\n");printf("%d\n",n - 1);for(int i = vec.size() - 1;i >= 0;i--) {printf("%d %d\n",vec[i].first,vec[i].second);}}return 0; }CF1474F 1 2 3 4 …
題意:
題解:
代碼:
總結
以上是生活随笔為你收集整理的Codeforces Round #696的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一起开心寒假训练总复习
- 下一篇: 他们想把ChatGPT,做成下一代iPh