Codeforces Round #660 (Div. 2) / contest 1388

目录

        • A Captain Flint and Crew Recruitment
        • B Captain Flint and a Long Voyage
        • C Uncle Bogdan and Country Happiness
        • D Captain Flint and Treasure
        • E


A B C D E

( √:做出; ●:尝试未做出; ○:已补题 )


题目地址:https://codeforces.com/contest/1388

这一次的题目好难读懂题……然后题目难度不大,就是做得太慢了。



A Captain Flint and Crew Recruitment

题意:如果一个数 x 可以分解为 p ⋅ q p\cdot q pq 并且 p 和 q 都为质数且不相等的形式,那么 x 就是一个近似质数。现在给出一个正整数 n,问 n 能否分解成四个不同的数的和,使得这四个数中至少有三个是近似质数。

思路:真是具有欺骗性。其实只要找出最小的 4 个近似质数(分别是 6,10,14,15),然后分解就行了。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    int T=read();
    while(T--)
    {
        int n=read();
        if(n<=30) puts("NO");
        else
        {
            puts("YES");
            if(n-30==6 || n-30==10 || n-30==14) printf("6 10 15 %d\n",n-31);
            else printf("6 10 14 %d\n",n-30);
        }
    }

    return 0;
}



B Captain Flint and a Long Voyage

题意:水题。

思路

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

int main()
{
    int T=read();
    while(T--)
    {
        int n=read();
        int x=(n-1)/4+1;
        REP(i,1,n-x) putchar('9');
        REP(i,1,x) putchar('8');
        puts("");
    }

    return 0;
}



C Uncle Bogdan and Country Happiness

题意:题意好复杂。大致意思就是有一棵树,1 号是根结点,每个结点都是一座城市,每个结点都有若干个人居住。一开始所有人都在 1 号结点,心情为 good 或者 bad。现在每个人都要由最短路回家,在路上心情可能会从 good 变成 bad(但不会反向变)。每个结点都记录了一个值 h,表示经过这个结点的 good 的人数减去 bad 的人数。现在给出所有数据,问每个结点的 h 是否合法。

思路:计算每个结点的 size,根据 size 和 h 可以唯一确定经过这个结点 good 和 bad 的人数(或者说明不合法),然后因为人不可能从 bad 变成 good,所以一个结点的 good 的人数一定不会小于它儿子的 good 的人数之和。就在树上 dfs 一下就可以全部算出来了。

在这里记录一下我总是犯的一个错误:误以为 G[x].size()<=1 代表的就是叶子,殊不知也有可能是根结点,这个错误已经犯了好多次了。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=1e5+5;
VI G[maxn];
LL p[maxn],n,m,h[maxn],g[maxn],b[maxn],flag,siz[maxn];

void dfs(int u,int fa)
{
    siz[u]=p[u];
    for(int v:G[u]) if(v!=fa)
    dfs(v,u),siz[u]+=siz[v];
    LL x=(h[u]+siz[u])/2,y=x-h[u];
    if(x<0 || y<0 || x+y!=siz[u] || x-y!=h[u]) flag=0;
    g[u]=x; b[u]=y;
    LL sum=0;
    for(int v:G[u]) if(v!=fa) sum+=g[v];
    if(sum>g[u]) flag=0;
    //cout<
}

int main()
{
    int T=read();
    while(T--)
    {
        int n=read(),m=read(); flag=1;
        REP(i,1,n) G[i].clear(),g[i]=b[i]=siz[i]=0;
        REP(i,1,n) p[i]=read();
        REP(i,1,n) h[i]=read();
        REP(i,1,n-1)
        {
            int x=read(),y=read();
            G[x].pb(y); G[y].pb(x);
        }
        dfs(1,0);
        puts(flag?"YES":"NO");
    }

    return 0;
}



D Captain Flint and Treasure

题意:有两个数组 a 和 b( − 1 0 6 ≤ a i ≤ 1 0 6 -10^6\le a_i \le 10^6 106ai106 1 ≤ b i ≤ n   o r   b i = − 1 1\le b_i\le n\ or \ b_i=-1 1bin or bi=1),现在要对每个位置 i 按照如下方法操作一次:将 a i a_i ai 累加到 ans,然后如果 b i ≠ − 1 b_i\neq -1 bi=1,就令 a b i + = a i a_{b_i}+=a_i abi+=ai 。问最后 ans 的最大值,并且输出操作序列。

思路:其实也很简单,就是按照拓扑序进行操作。第一次拓扑序操作时,对于某个结点 i,如果 a i ≥ 0 a_i\ge 0 ai0,那么将其标记,累加答案并且将其加入 a b i a_{b_i} abi ,否则不对其进行标记;第二次拓扑序对所有没进行标记的进行处理,按照反拓扑序选择。其实思路就是贪心,如果正数就尽量累加到后面,如果负数就反向拓扑序,也就是不让它累加。

代码

#define DIN freopen("input.txt","r",stdin);
#define DOUT freopen("output.txt","w",stdout);
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define REP_(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> P;
int read()
{
    int x=0,flag=1; char c=getchar();
    while((c>'9' || c<'0') && c!='-') c=getchar();
    if(c=='-') flag=0,c=getchar();
    while(c<='9' && c>='0') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return flag?x:-x;
}

const int maxn=2e5+5;
VI an;
LL a[maxn],b[maxn],ans;
int n,vis[maxn],du[maxn],nxt[maxn];

int main()
{
    n=read();
    REP(i,1,n) a[i]=read();
    REP(i,1,n) b[i]=read();
    REP(i,1,n) if(b[i]!=-1) nxt[i]=b[i],du[b[i]]++;

    queue<int> que;
    REP(i,1,n) if(!du[i]) que.push(i);
    while(!que.empty())
    {
        int i=que.front(); que.pop();
        if(vis[i]) continue;
        if(a[i]>=0)
        {
            vis[i]=1;
            an.pb(i);
            ans+=a[i];
            if(nxt[i]>0) a[nxt[i]]+=a[i];
        }
        if(nxt[i]>0) du[nxt[i]]--;
        if(nxt[i]>0 && du[nxt[i]]==0) que.push(nxt[i]);
    }
    stack<int> st;
    REP(i,1,n) du[i]=0;
    REP(i,1,n) if(!vis[i] && nxt[i]>0) du[nxt[i]]++;
    REP(i,1,n) if(!vis[i] && !du[i]) que.push(i);
    while(!que.empty())
    {
        int i=que.front(); que.pop();
        vis[i]=1;
        st.push(i);
        ans+=a[i];
        if(nxt[i]>0) du[nxt[i]]--;
        if(nxt[i]>0 && !du[nxt[i]] && !vis[nxt[i]]) que.push(nxt[i]);
    }
    while(!st.empty()) an.pb(st.top()),st.pop();

    printf("%lld\n",ans);
    for(int i:an) printf("%d ",i);

    return 0;
}



E

题意

思路

代码


你可能感兴趣的:(codeforces)