[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时,说明所有特殊结点一已经联通,之后的边都不会影响答案,而最后一条边一定连接了两个特殊结点,所以这条边的权值就是所有的最大值。

猜你喜欢

转载自www.cnblogs.com/xutianshu/p/10173304.html