NOI Online #3 入门组题解

T1 最急救助

洛谷传送门
第一题还是一如既往的水233
没什么好说的。
统计每一条信号。对于一个信号,统计sos的数量,方法就是枚举每一个长度为3的区间,如果这个区间是“sos”那么就统计进去。取最大数量。
有一个小坑,就是最大可能有多个,要用vector存储。

#include 
using namespace std;
#define MAXN 105
#define MAXM 205
int n,maxx;
vector<string> max_name;
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        string name,sig;
        int cnt=0;
        cin>>name>>sig;
        for(int i=0;i<sig.size()-2;i++){
            if(sig[i]=='s'&&sig[i+1]=='o'&&sig[i+2]=='s'){
                cnt++;
            }
        }//统计sos数量
        if(cnt>maxx){
            max_name.clear();
            maxx=cnt;
            max_name.push_back(name);//如果有比它更大的,就把vector清空再把它塞到vector里
        }else if(cnt==maxx){
            max_name.push_back(name);//如果它就是最大的,那么就把它塞到vector里
        }
    }
    for(int i=0;i<max_name.size();i++){
        cout<<max_name[i]<<' ';
    }
    cout<<endl<<maxx<<endl;
    return 0;
}

T2观星

洛谷传送门
这道题…也比较水
可以搜索出每个星座。对于每个星座,要分配给合适的星系,再取最大的星系输出
注意:星系的大小=星座数*星座大小

#include 
using namespace std;
#define MAXN 1505
#define MAXS 100005
int n,m,a[MAXN][MAXN],cnt/*当前星座大小*/,s[MAXS]/*星座大小为i的星系*/,ans1/*有多少星系*/,ans2/*最大星系多大*/;
int next[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
bool vis[MAXN][MAXN];
void dfs(int x,int y){
    cnt++;
    vis[x][y]=1;
    for(int i=0;i<8;i++){
        if(!vis[x+next[i][0]][y+next[i][1]]&&a[x+next[i][0]][y+next[i][1]]){
            dfs(x+next[i][0],y+next[i][1]);
        }
    }
}
int main(){
    //freopen("star.in","r",stdin);
    //freopen("star.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        char in[MAXN];
        scanf("%s",in+1);
        for(int j=1;j<=m;j++){
            if(in[j]=='.'){
                a[i][j]=0;
            }else{
                a[i][j]=1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!vis[i][j]&&a[i][j]){//如果当前星星不属于已知的任何一个星座,
                                    //那么这个星星一定属于一个新的星座
                cnt=0;
                dfs(i,j);//把这个新的星座搜索出来
                s[cnt]++;//把新的星座分配给合适的星系
            }
        }
    }
    for(int i=1;i<MAXS;i++){
        if(s[i]){
            ans1++;
            ans2=max(ans2,i*s[i]);
        }
    }//统计,没什么好说的
    printf("%d %d\n",ans1,ans2);
    return 0;
}

T3 买表

洛谷传送门
ccf我去年买了个表
首先,一堆一样的钞票可以通过二进制压缩这个东西压缩成一堆面额不一样但数量少得多的钞票。
二进制压缩,就是把钞票1个一组、2个一组、4个一组地分组,因为都是2^n张,每一组选或不选可以对应到二进制数里的每一位0和1,所以二进制压缩后的一堆钞票可以表示1~总数的任意张原来的钞票。
如果分组后剩下一些,直接把剩下的分成一组就可以啦。
Hmm…然后就转换成了凑数问题,凑数用0-1背包就可以了。
01背包传送门
凑数怎么转化成背包?
把凑数目标看成背包问题里的背包容量,
再把每张钞票的面额看做物品的重量和价值,
求一遍01背包,如果dp[i]=i,那么可以凑出价值为i的价格,因为dp[i]是上限为i的最大价格,如果最大价格不等于上限,就凑不出来。

#include 
using namespace std;
#define MAXN 2000
#define MAXM 100005
#define MAXT 500005
int _n,n,m,note[200000],dp[MAXT];
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d%d",&_n,&m);
    for(int i=1;i<=_n;i++){
        int k,a,tmp,cnt=1,cnt2=0;
        scanf("%d%d",&k,&a);
        tmp=1;
        while(cnt<a){
            note[++n]=tmp*k;
            cnt+=tmp*2;
            cnt2+=tmp;
            tmp*=2;
        }
        if(a-cnt2>0){
            note[++n]=(a-cnt2)*k;
        }
    }//二进制压缩
    for(int i=1;i<=n;i++){
        for(int j=500000;j>=note[i];j--){
            dp[j]=max(dp[j],dp[j-note[i]]+note[i]);
        }
    }//01背包
    for(int i=1;i<=m;i++){
        int in;
        scanf("%d",&in);
        if(dp[in]==in){
            printf("Yes\n");
        }else{
            printf("No\n");
        }
    }
    return 0;
}

最后,祝点赞的人都能AKIOI!23333333

你可能感兴趣的:(题解)