“深圳计算科研院杯“E起来编程暨第三届湖北省赛题解

A.A Warm Welcome

  • 解题思路

    签到题,直接输出赞助商完整的英文名称即可。

  • AC代码

/**
  *@filename:A
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: [email protected]
  *@created: 2021-05-05 18:57
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

string s;
void solve(){
     
}
int main(){
     
    cin>>s;
    cout<<"Shenzhen Institute of Computing Sciences"<<endl;
    solve();
    return 0;
}

B.Mr.Maxwell and attractions

  • 解题思路

    我们首先要清楚的是,选择上午玩和下午玩的区别在于下午玩的室外景点的魅力值会降成 0.8 0.8 0.8,所以我们如果选择去室外,则更偏向与上午去。而题目中限制了上午工作的天数要 > = k >=k >=k,即下午游玩的次数必须 > = k >=k >=k。而由于下午会有折扣,所以我们实际上只会选择下午去游玩 k k k次即可。 那么根据贪心原则,我们肯定是先选择去魅力值最多的地方。那么我们可以用两个优先队列来维护当前室内室外景点魅力值的最大值(由于观赏过一次魅力值会变成 0.6 0.6 0.6,所以我们需要更新访问过的魅力值)。 故我们模拟判断即可,注意,我们需要尽可能的选择下午,消耗掉 k k k。具体看 A C AC AC代码。

  • AC代码

/**
  *@filename:B
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: [email protected]
  *@created: 2021-05-05 19:01
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n,m,t,k;
double a[maxn],b[maxn];//a代表的是户内景点,b代表的是户外景点。需要注意的是户外景点在下午会降到0.8
priority_queue<double> q1,q2;
void solve(){
     
    //题目意思也就是说选择的下午游玩的次数必须大于等于k。由于下午会有折扣,所以我们实际上只会选择下午去游玩k次即可。
    double ans=0;
    for(int i=1;i<=t;i++){
     
        double u=q1.top(),v=q2.top();
        //我们需要判断我们是否还能选择上午游玩。
        q1.pop(),q2.pop();
        if(i+k<=t){
     
            //说明还可以上午去游玩,我们需要判断去室内还是取室外。
            if(u>=v){
     
                //说明室内大于室外,那么我们实际上这时候就可以选择下午出发了,消耗k。
                ans+=u;
                q1.push(u*0.6),q2.push(v);
                k--;
            }
            else{
     
                //为了不折扣,我们选择上午出发。
                ans+=v;
                q1.push(u),q2.push(v*0.6);
            }
        }
        else{
     
            //说明必须下午出发。我们判断去室内还是室外。
            if(u>0.8*v){
     
                ans+=u;
                q1.push(u*0.6),q2.push(v);
            }
            else{
     
                ans+=v*0.8;
                q1.push(u),q2.push(v*0.6);
            }
        }
    }
    printf("%.2f\n",ans);
}
int main(){
     
    cin>>n>>m>>t>>k;
    for(int i=1;i<=n;i++){
     
        cin>>a[i];
        q1.push(a[i]);
    }
    for(int i=1;i<=m;i++){
     
        cin>>b[i];
        q2.push(b[i]);
    }
    solve();
    return 0;
}

C.Hamster and Equation

  • 解题思路

    利用 m a p map map存储左边的 F ( x 1 , x 2 ) F(x_1,x_2) F(x1,x2)所有可能的值,然后再利用 F ( x 1 , x 2 ) = K ∗ ( F ( x 3 , x 4 ) ) F(x_1,x_2)=K*(F(x_3,x_4)) F(x1,x2)=K(F(x3,x4)),枚举 x 3 , x 4 x_3,x_4 x3,x4统计对应 F ( x 1 , x 2 ) F(x_1,x_2) F(x1,x2)出现的次数即可。

  • AC代码

/**
  *@filename:C
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: [email protected]
  *@created: 2021-05-05 20:48
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int t,n,k;
map<ll,int> p;
void solve(){
     
    for(int i=-n;i<=n;i++){
     
        for(int j=-n;j<=n;j++){
     
            p[i*i+i+j*j+j]++;
        }
    }
    ll ans=0;
    for(int i=-n;i<=n;i++){
     
        for(int j=-n;j<=n;j++){
     
            ans+=p[(i*i+i+j*j+j)*k];
        }
    }
    cout<<ans<<endl;
}
int main(){
     
    cin>>t;
    while(t--){
     
        cin>>n>>k;
        p.clear();
        solve();
    }
    return 0;
}

D.WA

  • 解题思路

    贪心题,我们总想最大程度的利用已有的 a a a字符,那么我们优先是将 a a a之间的间隔字符全部更改为 a a a,所以我们可以将这些间隔信息统计出来,再根据间隔大小排序即可,当然也可以利用优先队列。然后,最大程度的填充掉间隔。 处理完之后,由于没有间隔可以填补完,我们现在只需要更改 a a a旁边相邻的字符即可。注意需要两个方向遍历,即将 a b b b b abbbb abbbb b b b b a bbbba bbbba这种都得考虑上。同时,此题值得注意的一个坑点就是原字符串中若没有 a a a字符,我们需要先让其中一个字符变为 a a a(前提是 k > 0 k>0 k>0),再遍历填充。

  • AC代码

/**
  *@filename:D
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: [email protected]
  *@created: 2021-05-06 20:12
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 500000 + 5;
const int mod = 1e9+7;

int n,k;
char s[maxn];
struct node{
     
    int l,r,w;
    bool operator<(const node temp)const {
     
        return w>temp.w;//由于我们需要放到优先队列中,而默认是大顶堆,所以我们需要这样设置。
    }
};
priority_queue<node> q;
void solve(){
     
    int pre=0;
    node temp;
    for(int i=1;i<=n;i++){
     
        if(s[i]=='a'){
     
            if(pre){
     
                //说明现在存在a。
                temp.l=pre+1,temp.r=i-1,temp.w=i-pre-1;
                q.push(temp);
            }
            pre=i;//记录先前的a下标。
        }
    }
    //我们需要将这间隔补全。
    while(!q.empty()){
     
        temp=q.top();
        q.pop();
        if(temp.w>k){
     
            //说明间隔补不全。
            break;
        }
        k-=temp.w;
        for(int i=temp.l;i<=temp.r;i++){
     
            s[i]='a';
        }
    }
    //接下来需要补全没有填的,如果字符串中不存在a,我们自己需要构造。
    if(pre==0&&k){
     
        s[1]='a';
        k--;
    }
    for(int i=1;i<=n;i++){
     
        //从前往后看。
        if(k&&s[i]!='a'&&s[i-1]=='a'){
     
            s[i]='a';
            k--;
        }
    }
    for(int i=n;i>=1;i--){
     
        if(k&&s[i]!='a'&&s[i+1]=='a'){
     
            s[i-1]='a';
            k--;
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
     
        if(s[i]==s[i+1]&&s[i]=='a')cnt++;
    }
    cout<<cnt<<endl<<s+1<<endl;
}
int main(){
     
    cin>>n>>k>>s+1;
    solve();
    return 0;
}

E.Pipeline Maintenance

  • 解题思路

    知识漏洞,待补。

F.Meet in another world, enjoy tasty food!

  • 解题思路

    模拟题,但不是简单的题意模拟,我们是一次模拟能将最小的 x x x变为 0 0 0的操作。所以我们每次可以找到最先变为 0 0 0的那个值,找到之后就可以模拟了,根据操作数来对每个值进行更改。据此题易解。

  • AC代码

/**
  *@filename:F
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: [email protected]
  *@created: 2021-05-05 20:14
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n;
queue<ll> q;
ll x[maxn];
bool vis[maxn];//vis[i]代表i已经出队。
ll cal(ll x,ll k){
     
    //x代表的为其耐力值,k代表是每次减少的耐力值,返回的即是需要进行的操作数。
    return x/k+(x%k!=0);
}
void solve(){
     
    //我们肯定不是一次一次的模拟,而是模拟能将最小的x变为0的操作。
    int t=1;//t为计数操作。
    ll s=0;//当前需要减少的耐力值。
    vector<int> result;
    while(t<=n){
     
        //找到最小的那个。
        ll idx=0,temp=0;//idx保存的即是最小耐力值的下标。temp保存的即是每次减少的耐力值。
        for(int i=1;i<=n;i++){
     
            if(vis[i])continue;
            s+=1;
            if(!idx||cal(x[idx],temp)>cal(x[i],s)){
     
                idx=i;
                temp=s;
            }
        }
        s=0;
        ll k=cal(x[idx],temp);//计算最小操作次数,开始更改所有的x。
        temp=0;//temp为弥补值,即当有一个已经出队了,那么temp需要弥补上s加上的1.
        for(int i=1;i<=n;i++){
     
            if(vis[i])continue;
            s+=1;
            ll dict=(k-1)*s+(s-temp);
            x[i]-=dict;
            if(x[i]<=0){
     
                vis[i]=true;
                result.push_back(i);
                temp++;
                t++;
            }
        }
    }
    for(int i=0;i<n;i++){
     
        cout<<result[i];
        i==n?cout<<endl:cout<<" ";
    }
}
int main(){
     
    scanf("%d",&n);
    ll temp;
    for(int i=1;i<=n;i++)scanf("%lld",&x[i]);
    solve();
    return 0;
}

你可能感兴趣的:(竞赛,算法,队列,数据结构)