《第二届太原理工大学程序设计新生赛决赛》

没人写题解..那我来水一发.
A:博弈论。
可以发现连续的一段可以看成一样的。
那么由于1起手。
所以如果两边都是黑。相当于后手变先手。
然后统计下能操作的次数为奇偶即可。
Code:

void run()
{
    int n;sd(n);
    string s;cin >> s;
    char c = s[n-1];
    int ma = 0;
    for(int i = n-2;i >= 0;--i)
    {
        if(s[i] != c)
        {
            ma++;
            c = s[i];
        }
    }
    if(ma == 0)
    {
        if(c == '1') printf("Qiy win\n");
        else printf("Vanis win\n");
    }
    else if((ma&1) || (s[n-1] == '1' && s[0] == '1')) printf("Qiy win\n");
    else printf("Vanis win\n");
}  
int main()
{
    run();
    //system("pause");
    return 0;
}

C:
栈模拟下。
Code:

void run()
{
    int n;sd(n);
    string s1,s2;
    cin >> s1 >> s2;
    int tot = 0;
    stack<int> S;
    for(int i = 0;i < s1.size();++i)
    {
        S.push(s1[i]);
        while(!S.empty())
        {
            if(s2[tot] == S.top())
            {
                tot++;
                S.pop();
            }
            else break;
        }
    }
    bool f = true;
    while(!S.empty())
    {
        if(S.top() != s2[tot]) f = false;
        else tot++;
        S.pop();
    }
    if(f) printf("Yes\n");
    else printf("No\n");
}  
int main()
{
    run();
    //system("pause");
    return 0;
}

M:签到
Code:

void run()
{
    int a,b,c,d;
    sdd(a,b),sdd(c,d);
    if(a*c <= b) b = a*c;        
    int t = d/b;
    int ans = t*c;
    d -= t*b;
    ans += d/a;
    pr(ans);
}  
int main()
{
    run();
   // system("pause");
    return 0;
}

J:
一开始以为质数排列。
后面发现以一个数开始一直连续到它的2倍或者n肯定会存在最优的至少一种。
如果只有一种,那么把最大的偶数换成它的一半也是可以的。
Code:

int ans[N];
void run()
{
    int n;sd(n);
    int Maxx = -1,ma;
    for(int i = 1;i <= n;++i)
    {
        if(2*i <= n) ma = i;
        else ma = n-i+1;
        Maxx = max(Maxx,ma);
    }
    int cnt = 0;
    for(int i = 1;i <= n;++i)
    {
        if(2*i <= n) ma = i;
        else ma = n-i+1;
        if(ma == Maxx)
        {
            cnt++;
            for(int j = i;j <= i+ma-1;++j) ans[j-i+1] = j;
            for(int j = 1;j <= ma;++j) printf("%d%c",ans[j],j == ma ? '\n' :' ');
            if(cnt == 2) break;
        }
    }
    if(cnt != 2)
    {
        if(ans[Maxx] % 2 == 0) ans[Maxx] /= 2;
        else ans[Maxx-1] /= 2;
        for(int j = 1;j <= Maxx;++j) printf("%d%c",ans[j],j == Maxx ? '\n' :' ');
    }
}  
int main()
{
    run();
  //  system("pause");
    return 0;
}

L:
贪心:
可以发现对于凑成的方式只有三种。
A-B-C. A-B-C显然浪费更多,不可能有A-B-C优.
B-C-A.
C-A-B.
先凑成一种,然后将它转化为1半,而不是四份之一,肯定在之中之间更优。
那么这三种只要存在一个就YES.
Code:

int w[4];
bool cal(int a,int b,int c,int x,int y,int z)
{
    if(a >= w[x]) a -= w[x],b += a/2;
    else return false;
    if(b >= w[y]) b -= w[y],c += b/2;
    else return false;
    if(c < w[z]) return false;
    return true;
}
void run()
{
    int n,a,b,c;cin >> n >> a >> b >> c;
    for(int i = 1;i <= n;++i)
    {
        int t,ww;sdd(t,ww);
        w[t] += ww;
    }
    if(cal(a,b,c,1,2,3) || cal(b,c,a,2,3,1) || cal(c,a,b,3,1,2)) printf("YES\n");
    else printf("NO\n");
}  
int main()
{
    run();
    system("pause");
    return 0;
}

G:
树形问题。
可以发现肯定是到一个点然后走到这个点能延伸的最下面。
所以枚举从哪个点可以往下即可。
之前dp统计下i点向下的最大路径。
注意的是一个点能否上还需要满足x到这个点的时间小于1到这个点的时间,不然就会被抓到。
这个时间就树上距离求下。
注意MAXX赋为0,可能存在x = 1的情况。
Code:

int n,x,dp[N],dep[N],f[N][25],lg[N],ans = 0;
vector<int> G[N];
void init()
{
    for(int i = 1;i < N;++i) lg[i] = lg[i-1]+((1<<lg[i-1]) == i);
}
void dfs(int u,int fa)
{
    dep[u] = dep[fa]+1;f[u][0] = fa;
    for(int i = 1;i <= lg[dep[u]];++i) f[u][i] = f[f[u][i-1]][i-1];
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs(v,u);
        dp[u] = max(dp[u],dp[v]+1);
    }
}
int LCA(int x,int y)
{
    if(dep[x] < dep[y]) swap(x,y);
    while(dep[x] > dep[y])
    {
        x = f[x][lg[dep[x]-dep[y]]-1];
    }
    if(x == y) return x;
    for(int i = lg[dep[x]]-1;i >= 0;--i)
    {
        if(f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
    }
    return f[x][0];
}
int dis(int x,int y)
{
    return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
void dfs1(int u,int fa)
{
    int dis1 = dis(u,1),dis2 = dis(u,x);
    if(dis1 > dis2)
    {
        int ma = 2*dp[u]+2*dis1;
        ans = max(ans,ma);
    }
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs1(v,u);
    }
}
void run()
{
    init();
    sdd(n,x);
    for(int i = 1;i < n;++i)
    {
        int u,v;sdd(u,v);
        G[u].pb(v),G[v].pb(u);
    }
    dfs(1,0);
    dfs1(1,0);
    pr(ans);
}  
int main()
{
    run();
  //  system("pause");
    return 0;
}

H:
树形背包。比赛快结束的时候想到了。没时间写..
dp[i][j]表示到i点时,i点代价变为j的最小代价。
因为这样直接背包统计有N^3复杂度。
但可以发现对于j = x.
它的子节点为[0~x]都满足。所以递推过程中mixx记录最小值。
然后这个改变的代价先在每个点之前处理出来。
因为每个子节点都满足所以dp + 每个子节点满足的最小值。
注意j稍微比1000大一点点。(1000应该也可以把)
Code:

int n,a[1005];
vector<int> G[1005];
LL dp[1005][1005];
void dfs(int u,int fa)
{
    for(int j = 0;j < 1005;++j) dp[u][j] = abs(a[u]-j);
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs(v,u);
        LL mixx = INF;
        for(int j = 0;j < 1005;++j)
        {
            mixx = min(mixx,dp[v][j]);
            dp[u][j] += mixx;
        }
    }
}
void run()
{
    sd(n);
    for(int i = 1;i <= n;++i)
        for(int j = 0;j < 1005;++j) dp[i][j] = INF;
    for(int i = 1;i < n;++i)
    {
        int x;sd(x);
        G[x].pb(i+1);
        G[i+1].pb(x);
    }
    for(int i = 1;i <= n;++i) sd(a[i]);
    dfs(1,0);
    LL ans = INF; 
    for(int j = 0;j < 1005;++j) ans = min(ans,dp[1][j]);
    plr(ans);
}  
int main()
{
    run();
    //system("pause");
    return 0;
}

E题不会。。如果有会的大佬教下蒟蒻好吗

全部评论
代码又崩了..我裂开来
点赞 回复 分享
发布于 2020-06-14 20:03
懒得贴了,想看的直接去提交搜吧..
点赞 回复 分享
发布于 2020-06-14 20:04

相关推荐

11-04 14:10
东南大学 Java
_可乐多加冰_:去市公司包卖卡的
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务