Codeforces#584 A~F题解

A Paint the Numbers

题目

直接循环下

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
 
const int MAXN = 110;
int a[MAXN],ans;
int main()
{
    int n,i;
    scanf("%d",&n);
    for(i = 1;i <= n;i++)
        scanf("%d",&a[i]);
    sort(a + 1,a + 1 + n);
    for(i = 1;i <= n;i++)
    {
        bool able = 1;
        for(int j = 1;j < i;j++)
            if(a[i] % a[j] == 0)
            {
                able = 0;
                break;
            }
        if(able) ans++;
    }
    printf("%d",ans);
    return 0;
}

B Koala and Lights

题目

题目大意

有n盏灯(\(1≤n≤100\)) 每盏灯有两种状态(开或关),给定每盏灯的初始状态(一个01字符串 0-关,1-开)

接下来每盏灯对应给出它的\(a\)\(b(1≤a,b ≤5 )\)

这些灯在\(b+a*k (k\in [0,+\infty))\)时刻会改变状态

问 同一个时刻最多有多少灯同时亮着

因为\((1≤a,b ≤5 )\)

考虑一下这个范围 求一下lcm

大概暴力循环到200就够了

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
 
const int MAXN = 110;
bool sta[MAXN];
struct node
{
    int a,b;
}w[MAXN];
int ans;
int main()
{
    int j,i,n;
    scanf("%d",&n);
    for(i = 1;i <= n;i++) scanf("%1d",&sta[i]);
    for(i = 1;i <= n;i++)
        scanf("%d%d",&w[i].a,&w[i].b);
    for(i = 0;i <= 200;i++)
    {
        int q = 0;
        for(j = 1;j <= n;j++)
        {
            if(i >= w[j].b&&(i - w[j].b) % w[j].a == 0) sta[j] = !sta[j];
            if(sta[j]) q++;
        }
        ans = max(ans,q);
    }
    printf("%d",ans);
    return 0;
}

C Paint the Digits

题目

比较简单

用单调队列 处理完1的

但此时涂1不一定有这么多,判断一下涂2的最小的

把涂1的大于涂2的最小的数给添加到涂2里就搞定了

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
 
const int MAXN = 2e5 + 1;
int d[MAXN],cnt;
struct node
{
    int val,loc;
}q[MAXN];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,i,j;
        scanf("%d",&n);
        cnt = 0;
        q[cnt].val = -1;
        for(i = 1;i <= n;i++)
            scanf("%1d",&d[i]);
        for(i = 1;i <= n;i++)
        {
            while(q[cnt].val > d[i]) cnt--;
            q[++cnt].val = d[i];
            q[cnt].loc = i;
        }
        j = 1;
      //处理涂1的
        int fi = 0;
        for(i = 1;i <= n;i++)
        {
            if(d[i] == q[j].val&&j <= cnt) j++;
            else {
                fi = i;
                break;
            }
        }
        //找最小(不是指大小,而是位置)的涂2的
        if(fi)
        {
            while(q[cnt].val > d[fi]) cnt--;
            j = 1;
            bool able = 0;
            int maxl = 0;
            for(i = 1;i <= n;i++)
                if(d[i] == q[j].val&&j <= cnt) j++;
                else {
                    maxl = max(maxl,d[i]);
                    if(d[i] < maxl)
                    {
                        able = 1;
                        break;
                    }
                }
            if(able)
            {
                printf("-\n");
                continue;
            }
        }
        j = 1;
        for(i = 1;i <= n;i++)
            if(d[i] == q[j].val&&j <= cnt) {printf("1");j++;}
            else printf("2");
        putchar('\n');
    }
    return 0;
}

D Cow and Snacks

相当于是一个森林

易得每一棵树最大解为边数\(-1\)

然后再累加起来用\(n\)减它就是\(ans\)

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
 
const int MAXN = 1e5 + 1;
vector<int> G[MAXN];
int ans;
bool vis[MAXN],d[MAXN];
inline void dfs(int x)
{
    ans++;//
    vis[x] = 1;
    int i;
    for(i = 0;i < G[x].size();i++)
    {
        int v = G[x][i];
        if(!vis[v])
            dfs(v);
    }
}
int main()
{
    int i,n,k;
    scanf("%d%d",&n,&k);
    for(i = 1;i <= k;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
        d[u] = d[v] = 1;
    }
    for(i = 1;i <= n;i++)
        if(!vis[i]&&d[i])
        {
            dfs(i); 
            ans--;
        }       
    printf("%d",k - ans);
    return 0;
}

E Rotate Columns (easy version)

这道题对我来说不是很简单

因为这道题要用状压\(DP\)

而我没学

\(\color{pink}{然而学会之后还是挺简单的}\)

其实就是把一维记录状态

而这状态为\(10\)进制数

把她转为二进制

得到一个\(01\)字符串

分别对应每一列的状态

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int num[15][2010],dp[2010][4100],n;
inline int count(int x,int s)
{
    int i,j,ans = 0;
    for(i = 1;i <= n;i++)
    {
        int sum = 0,k = 1;
        for(j = 1;j <= n;j++)
        {
            if(k & s)
                sum += num[j][x];
            k <<= 1;
        }
     当前的取值
        ans = max(ans,sum);
        for(j = n;j >= 1;j--)
            num[j + 1][x] = num[j][x]; 
        num[1][x] = num[n + 1][x];
      把数字往后移一位
      
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,m;
        scanf("%d%d",&n,&m);
        for(i = 1;i <= n;i++)
            for(j = 1;j <= m;j++)
                scanf("%d",&num[i][j]); 
        int maxl = (1 << n) - 1,k;
      到这里 应该很容易看出来了
      
      dp[i][j]表示在前i列中 选取状态为j的最优解
        for(i = 1;i <= m;i++)
        {
            memset(dp[i],0,sizeof(dp[i]));
            for(j = 0;j <= maxl;j++)
            {
                for(k = j;;k = (k - 1) & j)
                {
                    dp[i][j] = max(dp[i][j],dp[i - 1][k] + count(i,j - k));
                    if(!k) break;
                }
            }
        }
        DP
        printf("%d\n",dp[m][maxl]);
    }
    return 0;
}

F Rotate Columns (hard version)

\(E\)题的话这题就很好做了

\(\color{pink}{大水题}\)

把每列的最大值记录下 按其大小从大到小排序

然后只算前\(n\)

还有就是 把\(count(i,j - k)\)预处理一下

但我的代码真的很神奇

讲道理循环到\(n\)就可以AC了

我改成\(n+5\)才过

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int num[15][2010],dp[2010][4100],n;
int cnt[2010][4100];
struct node
{
    int maxl,it;
    bool operator <(const node y) const {return maxl > y.maxl;}
}row[2010];
inline int count(int x,int s)
{
    int i,j,ans = 0;
    for(i = 1;i <= n;i++)
    {
        int sum = 0,k = 1;
        for(j = 1;j <= n;j++)
        {
            if(k & s) sum += num[j][row[x].it];
            k <<= 1;
        }
        ans = max(ans,sum);
        for(j = n;j >= 1;j--)
            num[j + 1][row[x].it] = num[j][row[x].it]; 
        num[1][row[x].it] = num[n + 1][row[x].it];
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,m;
        scanf("%d%d",&n,&m);
        for(i = 1;i <= n;i++)
            for(j = 1;j <= m;j++)
            {
                scanf("%d",&num[i][j]);
                if(i == 1) row[j].it = j,row[j].maxl = num[i][j];
                row[j].maxl = max(row[j].maxl,num[i][j]);
            }
        memset(cnt,0,sizeof(cnt));
        sort(row + 1,row + 1 + m);
        int maxl = (1 << n) - 1,k,ans = 0;
        for(i = 1;i <= min(n + 5,m);i++)
            for(j = 0;j <= maxl;j++)
                cnt[i][j] = count(i,j); 
        for(i = 1;i <= min(n + 5,m);i++)
        {
            memset(dp[i],0,sizeof(dp[i]));
            for(j = 0;j <= maxl;j++)
            {
                for(k = j;;k = (k - 1) & j)
                {
                    dp[i][j] = max(dp[i][j],dp[i - 1][k] + cnt[i][j - k]);
                    ans = max(ans,dp[i][j]);    
                    if(!k) break;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

G Koala and Notebook

这题得用拆点

之前没学过 然后这次学会了

所以打比赛使人进步

拆点的思路很简单

拆点的本质是拆边

我们这道题 把每条边 拆成 其位数条边 每条边的权值为其对应该位的数


输入
for(i = 1;i <= m;i++)
    {
        int j,u,v,k = i;
        scanf("%d%d",&u,&v);
        edge.clear();
        while(k) {edge.push_back(k % 10);k /= 10;}
        int Size = edge.size(),pre = u;
        for(j = Size - 1;j >= 0;j--)
        {
            int w = (j == 0? v:++cnt);
            V[pre][edge[j]].push_back(w);
            pre = w;
        }
        pre = v;
        for(j = Size - 1;j >= 0;j--)
        {
            int w = (j == 0? u:++cnt);
            V[pre][edge[j]].push_back(w);
            pre = w;
        }
    }

然后 我是用循环模拟的\(BFS\)

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 1e6 + 1;
const int MOD = 1e9 + 7; 
vector<int> edge,V[MAXN][10],Q[MAXN];
int ans[MAXN];
bool vis[MAXN];
int main()
{
    int i,n,m,cnt,j;
    scanf("%d%d",&n,&m);
    cnt = n;
    for(i = 1;i <= m;i++)
    {
        int j,u,v,k = i;
        scanf("%d%d",&u,&v);
        edge.clear();
        while(k) {edge.push_back(k % 10);k /= 10;}
        int Size = edge.size(),pre = u;
        for(j = Size - 1;j >= 0;j--)
        {
            int w = (j == 0? v:++cnt);
            V[pre][edge[j]].push_back(w);
            pre = w;
        }
        pre = v;
        for(j = Size - 1;j >= 0;j--)
        {
            int w = (j == 0? u:++cnt);
            V[pre][edge[j]].push_back(w);
            pre = w;
        }
    }
    int dep = 0;
    Q[++dep].push_back(1);
    vis[1] = 1;
    for(i = 1;i <= dep;i++)
        for(int w = 0;w < 10;w++)
        {
            bool able = 0;
            for(j = 0;j < Q[i].size();j++)
            {
                int u = Q[i][j];
                for(int k = 0;k < V[u][w].size();k++)
                {
                    int v = V[u][w][k];
                    if(vis[v]) continue;
                    vis[v] = able = 1;
                    Q[dep + 1].push_back(v);
                    ans[v] = (ans[u] * 10ll + w) % MOD;
                }
            }
            if(able) dep++;
        }
   BFS
    for(i = 2;i <= n;i++) printf("%d\n",ans[i]);
    return 0;
}

Sum up

后面三道题我也不会了

这次的题不难

但我的分数很低 只做对了AB题

值得反思

我也还需要多打比赛 多练题

把手感找到

转载于:https://www.cnblogs.com/resftlmuttmotw/p/11556630.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值