[CF]Avito Cool Challenge 2018
阿新 • • 發佈:2018-12-25
A(簽到)
題意:簽到
00:01 1A
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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++) constView Codeint 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; }
B(構造)
題意:有長度為n的數列B,Ai表示B中與Bi不同的值的數量,給出數列A,求B
顯然
1若Ai不同則Bi一定不同
2一定有n-Ai個數等於Bi
推出相同Ai的個數一定是n-Ai的倍數,其中每組n-Ai個Bi相等,否則無解,有解時方案按之前推論構造即可。
這題開始還沒想出來,不應該。。
01:12 2A
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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++) constView Codeint 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; }
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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時,說明所有特殊結點一已經聯通,之後的邊都不會影響答案,而最後一條邊一定連線了兩個特殊結點,所以這條邊的權值就是所有的最大值。