Jenkins 自動化部署詳解
- A. Special Permutation
- B. Unique Bid Auction
- C. Sequence Transformation
- D. Number into Sequence
- E. Number of Simple Paths
- F. Array Partition
A. Special Permutation
題意:
給出n,要求輸出一個1到n的全排列,需要滿足\(a_i\not=i\)
思路:
直接輸出2到n,最後輸出1即可
#include<bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int t,n; int main(){ cin>>t; while(t--){ cin >> n; for(int i=2;i<=n;i++){ cout<<i<<' '; } cout << 1; cout<<endl; } return 0; }
B. Unique Bid Auction
題意:
給出一個數組,要求輸出所有隻出現過一次的數中最小的數
思路:
直接求即可
#include<bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int t, n,a[N]; int main(){ cin >> t; while(t--){ cin>>n; map<int, int> mp; for (int i = 1; i <= n;i++){ cin >> a[i]; mp[a[i]]++; } int res = 0x3f3f3f3f; int pos = 0; for (int i = 1; i <= n;i++){ if(mp[a[i]]==1){ if(res>a[i]){ res = a[i]; pos = i; } } } if(res==0x3f3f3f3f){ cout << -1 << endl; } else{ cout << pos << endl; } } return 0; }
C. Sequence Transformation
題意:
給出一個數組,只能選擇一個數字x,然後每次都要消一個[L,R],[L,R]中不能包含x
問使得數列全相等的最少運算元
思路:
模擬題,讀入的時候直接判斷\(a_i\)和\(a_{i-1}\)是否相同以及是否是第一次出現,然後將對應的答案加一即可
#include<bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int t,n,a[N]; int main(){ cin>>t; while(t--){ cin>>n; map<int ,int >mp; for(int i=1;i<=n;i++){ cin>>a[i]; if(i!=1){ if(a[i]!=a[i-1]){ if(mp[a[i]]==0) mp[a[i]]++; mp[a[i - 1]]++; } } } int res=0x3f3f3f3f; for(int i=1;i<=n;i++){ res=min(res,mp[a[i]]); } cout<<res<<endl; } return 0; }
D. Number into Sequence
題意:
給出n,要求輸出最長的一組數,滿足它們的乘積能被n整除。而且\(a_i\)能夠整除\(a_{i-1}\)
思路:
質因子分解,找出出現次數x最多的質因子,先輸出前x-1個,最後乘上其他因數的乘積輸出。
#include <bits/stdc++.h>
using namespace std;
int const N = 1e7 + 10;
int n, m, T;
int prime[N], cnt;
int st[N];
long long sum = 0, res_val = 0,t,x;
void get_prime(int n) {
for (int i = 2; i <= n; ++i) {
if (!st[i]) prime[cnt++] = i; // 如果這個數字沒有被記錄,那麼這個數字必然為素數,記錄一下
for (int j = 0; prime[j] <= n/i; ++j) {
st[prime[j] * i] = true; // 篩掉pj*i這個合數
if (i % prime[j] == 0) break; // i%pj==0,說明pj是i的最小素因子,因此i*素數的最小素因子也是pj,在i遞增的時候也會被篩掉,因此不需要在這裡判斷
}
}
}
long long qmi(long long a, long long k) {
long long res = 1 ; // res記錄答案, 模上p是為了防止k為0,p為1的特殊情況
while(k) { // 只要還有剩下位數
if (k & 1) res = (long long)res * a ; // 判斷最後一位是否為1,如果為1就乘上a,模上p, 乘法時可能爆int,所以變成long long
k >>= 1; // 右移一位
a = (long long) a * a ; // 當前a等於上一次的a平方,取模,平方時可能爆int,所以變成long long
}
return res;
}
int main() {
get_prime(N - 1);
cin >> T;
while(T--) {
scanf("%lld", &x);
t = x;
sum = 0, res_val = 0;
for (int i = 0; prime[i] <= x / prime[i]; ++i) {
int p = prime[i];
if (x % p == 0) {
int s = 0;
while (x % p == 0) {
s++;
x /= p;
}
if ((long long)s > sum) {
sum = (long long)s;
res_val = p;
}
}
}
if (x > 1) {
if ((long long)1 > sum) {
sum = 1;
res_val = x;
}
}
cout << sum << endl;
if (sum == 1)
printf("%lld\n", t);
else
{
for (int i = 1; i <= sum - 1; ++i) printf("%lld ", res_val);
printf("%lld\n", (t / qmi(res_val, sum - 1)));
}
}
return 0;
}
E. Number of Simple Paths
大意:
給出一個n個點n條邊的無向圖,問從任意一個點走到其他任意一個點,有多少路徑,需要注意的是1->2->3與3->2->1視為相同的路徑
思路:
n個點n條邊的無向圖,被稱為基環圖,它可以看做一個基環再向外延伸出幾個樹的結構,如下圖:
對於同一個樹上的兩個點,只有1條路徑,所以每個樹提供了\(C_{num}^{2}\)個路徑(num為這棵樹的節點數),而對於不在同一個樹上的兩個點,因為需要經過基環,所以就存在從兩種經過環的方式,所以為2條路徑,所以我們可以先按照每對點都有2條路徑來做,然後刪掉每棵樹提供的路徑即可。
怎麼找環呢?利用拓撲排序,沒有被遍歷到的節點就一定在環上。最後再對環上的每個節點(即每棵樹的根節點)進行一遍dfs找出這棵樹的節點數即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t, n,du[N],istree[N],num[N];
vector<int> mp[N];
void dfs1(int now,int fa){
for (int i = 0; i < mp[now].size();i++){
int next = mp[now][i];
if(next==fa){
continue;
}
du[next]--;
du[now]--;
if(du[next]==1){
istree[next] = 1;
dfs1(next, now);
}
}
}
int dfs2(int now,int fa){
num[now] = 1;
for (int i = 0; i < mp[now].size();i++){
int next = mp[now][i];
if(next==fa)
continue;
if(istree[next]){
num[now] += dfs2(next, now);
}
}
return num[now];
}
int main(){
cin >> t;
while(t--){
cin >> n;
for (int i = 1; i <= n;i++){
mp[i].clear();
istree[i] = 0;
du[i] = 0;
}
for (int i = 1; i <= n ;i++){
int x, y;
cin >> x >> y;
mp[x].push_back(y);
mp[y].push_back(x);
du[x]++;
du[y]++;
}
for (int i = 1; i <= n;i++){
if(du[i]==1){
istree[i] = 1;
dfs1(i,0); //找環
}
}
LL res = n * ((LL)n - 1);
for (int i = 1; i <= n;i++){
if(istree[i]==0){
dfs2(i, 0); //找樹
res-=num[i] * ((LL)num[i] - 1)/2;
}
}
cout << res << endl;
}
return 0;
}
F. Array Partition
大意:
給出一個數組,要求將這個陣列分成長度分別為x,y,z(均不為0)的三部分,使得中間一部分的陣列最小值等於前後兩部分陣列的最大值,即:\(max(1, x) = min(x + 1, x + y) = max(x + y + 1, n)\)
思路:
首先單調棧維護每個位置上的數所控制的左右端點,直接找出現次數大於等於3的數,然後判斷這個數第一次出現的位置能否控制到最左邊,最後出現的位置能否控制最右邊,如果能就列舉中間出現的位置,看控制的區間是否有交集即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long LL;
int t, n,a[N],maxl[N],maxr[N],minl[N],minr[N];
int main(){
cin >> t;
while(t--){
cin >> n;
stack<int> st;
for (int i = 1; i <= n;i++){
scanf("%d", &a[i]);
}
for (int i = 1; i <= n;i++){
while(!st.empty()&&a[st.top()]>=a[i]){ //求以a[i]為最小值的左區間
st.pop();
}
if(st.empty()){
minl[i] = 0;
}
else{
minl[i] = st.top();
}
st.push(i);
}
while(!st.empty()){
st.pop();
}
for (int i = n; i >= 1;i--){
while(!st.empty()&&a[st.top()]>=a[i]){ //求以a[i]為最小值的右區間
st.pop();
}
if(st.empty()){
minr[i] = n+1;
}
else{
minr[i] = st.top();
}
st.push(i);
}
while(!st.empty()){
st.pop();
}
for (int i = 1; i <= n;i++){
while(!st.empty()&&a[st.top()]<=a[i]){ //求以a[i]為最大值的左區間
st.pop();
}
if(st.empty()){
maxl[i] = 0;
}
else{
maxl[i] = st.top();
}
st.push(i);
}
while(!st.empty()){
st.pop();
}
for (int i = n; i >= 1;i--){
while(!st.empty()&&a[st.top()]<=a[i]){ //求以a[i]為最大值的右區間
st.pop();
}
if(st.empty()){
maxr[i] = n+1;
}
else{
maxr[i] = st.top();
}
st.push(i);
}
unordered_map<int, vector<int> > mp;
unordered_map<int, int> no;
for (int i = 1; i <= n;i++){
mp[a[i]].push_back(i);
no[a[i]] = 0;
}
int flag = 0;
for (int i = 1; i <= n;i++){
if(flag)
break;
if(mp[a[i]].size()<3){
continue;
}
if(no[a[i]]==1){
continue;
}
int st = mp[a[i]][0], en = mp[a[i]][mp[a[i]].size()-1];
if(maxl[st]==0&&maxr[en]==n+1){
for (int j = 1; j < mp[a[i]].size() - 1;j++){
int mid = mp[a[i]][j];
if(minl[mid]+1<=maxr[st]&&minr[mid]-1>=maxl[en]){
flag = 1;
printf("YES\n");
int x = min(maxr[st]-1, mid-1);
int y = max(mid + 1, maxl[en]+1);
printf("%d %d %d\n", x, y - x - 1, n - y + 1);
break;
}
}
}
if(flag==0)
no[a[i]] = 1;
}
if(flag==0){
printf("NO\n");
}
}
return 0;
}