1. 程式人生 > >[CF]Avito Cool Challenge 2018

[CF]Avito Cool Challenge 2018

A(簽到)

題意:簽到

00:01 1A

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

#define st first
#define nd second
#define pb push_back
#define mp make_pair
#define pll pair <LL, LL>
#define pii pair <int, int>
#define rep(i,x) for(int i=1;i<=x;i++)

const
int N = 1e5+7; const int MX = 1e9+7; const LL INF = 1e18+9LL; int main(){ int x; cin>>x; if(x==2)cout<<2; else cout<<1; }
View Code

 

B(構造)

題意:有長度為n的數列B,Ai表示B中與Bi不同的值的數量,給出數列A,求B

顯然

1若Ai不同則Bi一定不同

2一定有n-Ai個數等於Bi

推出相同Ai的個數一定是n-Ai的倍數,其中每組n-Ai個Bi相等,否則無解,有解時方案按之前推論構造即可。

這題開始還沒想出來,不應該。。

01:12 2A

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

#define st first
#define nd second
#define pb push_back
#define mp make_pair
#define pll pair <LL, LL>
#define pii pair <int, int>
#define rep(i,x) for(int i=1;i<=x;i++)

const
int N = 1e5+7; const int MX = 1e9+7; const LL INF = 1e18+9LL; int a[N],sum[N],ans[N],lim[N]; vector<int> b[N]; int main(){ int n; cin>>n; rep(i,n){ scanf("%d",&a[i]); b[a[i]].pb(i); sum[a[i]]++; } for(int i=0;i<n;i++){ if(sum[i]%(n-i)){ cout<<"Impossible"; return 0; } lim[i]=n-i; } cout<<"Possible"<<endl; int cnt=1; for(int i=0;i<n;i++){ for(int j=0;j<b[i].size();j++){ ans[b[i][j]]=cnt; if((j+1)%lim[i]==0)cnt++; } } rep(i,n)cout<<ans[i]<<" "; return 0; }
View Code

 

C(dp)

題意:給n個方格塗m種顏色,有k個方格和左邊的方格顏色不同,求方案數。(n<=2000,m<=2000)

f[i][j]=f[i-1][j]+(m-1)*f[i-1][j-1],輸出f[n][k]即可。陣列可以滾動,但沒必要。O(nk)

或者直接推公式也不難

00:23 1A

#include <bits/stdc++.h>

using namespace std;

typedef long long int LL;

#define st first
#define nd second
#define pb push_back
#define mp make_pair
#define pll pair <LL, LL>
#define pii pair <int, int>
#define rep(i,x) for(int i=1;i<=x;i++)

const int N = 2e3+7;
const int MX = 1e9+7;
const LL INF = 1e18+9LL;
const LL mod=998244353;

LL dp[N][N];

int main(){
    int n,m,k;
    cin>>n>>m>>k;
    dp[0][0]=1;
    rep(i,n)
    for(int j=0;j<i&&j<=k;j++){
        if(j==0){
        dp[i][j]=m;
        continue;}
        dp[i][j]=((dp[i-1][j-1]*(m-1))%mod+dp[i-1][j])%mod;
    }
    cout<<dp[n][k];
}
View Code

 

D(MST)

題意:給出一個加權無向圖,有k個特殊結點。定義路徑長度為路徑上的最大邊權,求這k個結點到其他特殊結點最短路的最大值。

定義開始看起來很繞,後來一想其實類似貨車運輸。首先最短路一定在最小生成樹上取到,觀察樣例可以猜想所有最大值相等。事實上,考慮kruskal演算法過程,當一條邊被加入時,如果他兩邊的並查集都含有特殊結點,那麼答案一定不比這條邊小,因為樹上的路徑唯一,兩邊的特殊結點間的路徑一定包含這條邊,據此也可發現所有結點的答案一定都相等。所以只需在kruskal執行時維護每個並查集的大小,當有一個並查集大小為k時,說明所有特殊結點一已經聯通,之後的邊都不會影響答案,而最後一條邊一定連線了兩個特殊結點,所以這條邊的權值就是所有的最大值。