Codeforces Round 259(Div. 2)


layout: post
title: Codeforces Round 259(Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
---

传送门

A - Little Pony and Crystal Mine (签到画图

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const int inf=1e9;
typedef unsigned long long ull;


int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    int mid=n/2;
    for(int i=1;i<=mid;i++){
        for(int j=1;j<=n;j++){
            if(j<=mid-i+1||j>=mid+i+1)cout<<'*';
            else cout<<'D';
        }
        cout<<endl;
    }
    for(int i=1;i<=n;i++)cout<<'D';cout<<endl;
    for(int i=mid;i;i--){
        for(int j=1;j<=n;j++){
            if(j<=mid-i+1||j>=mid+i+1)cout<<'*';
            else cout<<'D';
        }
        cout<<endl;
    }

    return 0;
}

B - Little Pony and Sort by Shift

题意

给你一个数列 你每次可以把最后一个移到第一个问你最少几次可以把这个数列变成非递减的

思路

直接找到一个最小的然后判断顺时针能否相连 如果多个最小就直接-1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const int inf=1e9;
typedef unsigned long long ull;

int a[maxn];
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    int pre,flag=0,pos;
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(i&&a[i]<a[i-1])flag++,pos=i;
    }
    if(!flag)puts("0");
    else if(flag==1&&a[0]>=a[n-1])cout<<n-pos<<endl;
    else cout<<-1<<endl;
    return 0;
}

A - Little Pony and Expected Maximum (概率)

题意

投M面筛,分别求出最大投出i面的可能性

思路

直接判断太复杂 转换方向,发现求出一个筛子投出小于等于i很好算就等于i/m 然后n个一样的就n方

然后最大投出i面 =投出小于等于i面-投出小于等于i-1面

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
typedef unsigned long long ull;
double dp[maxn];

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int m,n;
    cin>>m>>n;
    for(int i=1;i<=m;i++)dp[i]=pow(i*1.0/m,n);

    double ans=0;
    for(int i=1;i<=m;i++){
        ans+=(dp[i]-dp[i-1])*i*1.0;
    }
    cout<<fixed<<setprecision(10)<<ans<<endl;

    return 0;
}

B - Little Pony and Harmony Chest (dfs+状态压缩+数论)

题意

给你一个数组a 然后给你一个数组b 让你组成构成一个数组b使得数组b任意两个数的gcd=1 并且数组b和a的对应元素绝对值最小 (数组a的值小于等于30)

思路

首先发现b的值最大到60,因为如果超过60 那么还不如直接选1来的好又没有贡献公约数又没有增加值

发现60内最多17个素数

我们就枚举整个数组b的当前素数个数种类就行

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const int inf=1e9;
typedef unsigned long long ull;

int prime[17]={2,3,5,7,11,13,17,19,23,29,31,37,39,41,43,47,53};
int dp[105][1<<17],pre[105][1<<17],num[105][1<<17];
int sta[70];
int a[150];

void dfs(int pos,int st){
    if(pos==1){
        cout<<pre[pos][st]<<" ";
        return ;
    }
    dfs(pos-1,st^(sta[pre[pos][st]]));
    cout<<pre[pos][st]<<" ";
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=2;i<60;i++){
        for(int j=0;j<17;j++){
            if(i%prime[j]==0)sta[i]|=(1<<j);
        }
    }
    for(int i=0;i<105;i++){
        for(int j=0;j<(1<<17);j++)dp[i][j]=inf;
    }
    dp[0][0]=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<(1<<17);j++){
            if(dp[i][j]==inf)continue;
            for(int k=1;k<60;k++){
                if(j&sta[k])continue;
                int now=j|sta[k];
                if(dp[i+1][now]>dp[i][j]+abs(a[i]-k)){
                    dp[i+1][now]=dp[i][j]+abs(a[i]-k);
                    pre[i+1][now]=k;
                }
            }
        }
    }
    int st;
    int mx=inf;
    for(int i=0;i<(1<<17);i++){
        if(dp[n][i]<mx){
            mx=dp[n][i];
            st=i;
        }
    }
    dfs(n,st);
    return 0;
}

C - Little Pony and Summer Sun Celebration (构造 dfs)

题意

给出有n个点m条路的图,再给出一组序列如果第i个数为零表明第i个点要被访问偶数次否则要被访问奇数次,如果存在这样的路径请输出出来,否则输出-1

思路

遍历图中每个点

找一个需要经过奇数次的点开始深搜。不用担心环,比如1-2-3-1是环,走1-2-3-2-1就行。进入一个点,先把它加进队列,经过次数为1;每次探完一条边回溯的时候,先把当前点再加入队列一次(走回来了嘛),然后看这条边连的那个点的经过次数够不够,不够的话再走它一下,再回来。(把那个点加入队列,再把这个点加入队列)。

只有起点可能次数不太对,如果不对的话就不走最后回起点的那一步了也就是删掉队尾

这样其实每条边不可能走超过4n次。最后把队列输出就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=2e5+50;
const int inf=1e9;
typedef unsigned long long ull;
vector<int>G[maxn];
vector<int>ans;

int a[maxn];
bool vis[maxn];
void dfs(int now,int pre){
    a[now]^=1;
    ans.push_back(now);
    vis[now]=1;
    for(auto i:G[now]){
        if(i!=pre&&vis[i]==0){
            dfs(i,now);
            ans.push_back(now);
            a[now]^=1;
            if(a[i]){
                ans.push_back(i);a[i]^=1;
                ans.push_back(now);a[now]^=1;
            }
        }
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    int root=-1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i])root=i;
    }
    if(root==-1)puts("0"),exit(0);
    dfs(root,-1);
    if(a[root])ans.pop_back(),a[root]^=1;
    for(int i=1;i<=n;i++){
        if(a[i])puts("-1"),exit(0);
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++)
        cout<<ans[i]<<" ";
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luowentao/p/10482746.html