写在前面,这场比赛是这个暑假最后一场多校比赛了,打得很不好,特别是在杭电的比赛,总是感觉水土不服一样。感觉自己比赛的时候总喜欢看榜,怎么说呢,看榜有看榜的好处吧,但是感觉在牛客和杭电的几场比赛都被榜带偏了,赛后补题的时候我觉得这题我是可以做出来的。说这么多,关键还是自己的比赛时的心态有问题,别一天天的盯着榜看,我觉得以后也要改正一下比赛时看榜的习惯了(或者说以后坚决不看榜),会做的总会做,不会做的看一辈子还是那样。

Mine Sweeper

题意:给出一个数s,构造出一个类似于扫雷游戏那种的矩阵,使得矩阵中所有数字之和为s。
思路:这题其实比赛时的思路已经很接近了,只是还是想复杂了一些,与官方题解的思路想到过一样的,但很快就想当然的否决了。这个题目其实如果用wps的表格进行模拟的话我觉得效果会更好。首先,当s<25的时候,我们就可以构造出X.X.X.X.类似这种的一行的矩阵出来,当s>25的时候,我们先这样考虑,对于一个完整的九宫格的话,我们只要在中心位置加上一个X,就相当于造成了增加8的贡献,
图片说明
即使最大到1000的话我们也只需要125个这样的九宫格。如果构造完整的25X25的矩阵的话,那么就可以构造出12X12=144个这种的九宫格,这显然是够的,所以我们就看输入的s中有几个8,然后就构造出几个九宫格就行了,对于余数的情况,我们只要适当的添加一些X进去就行了。最后我们可以证明到不管s为多少我们都有最终的答案。
对于余数的情况,只要看代码,然后再用wps表格验证一下就行了,其实方法有很多。
代码:

#include<bits/stdc++.h>
using namespace std;
char c[30][30];
char b[30];
int s;
void deal1(){
    for(int i=1;i<=25;i++){
        if(i&1) b[i]='X';
        else b[i]='.';
    }
    cout<<"1 "<<s+1<<endl;
    for(int i=1;i<=s+1;i++){
        cout<<b[i];
    }
    cout<<endl;
}
void deal2(){
    int k1=s/8;
    int k2=s%8;
    int x=2,y=2;
    while(k1>0){
        c[x][y]='X';
        y+=2;
        if(y>24){
            x+=2;
            y=2;
        }
        k1--;
    }
//对余数进行处理
    if(k2==1)  c[1][1]='X';
    if(k2==2)  c[1][1]=c[1][2]='X';
    if(k2==3)  c[1][2]='X';
    if(k2==4)  c[2][3]='X';
    if(k2==5)  c[1][1]=c[2][3]='X';
    if(k2==6)  c[25][25]=c[25][24]='X';
    if(k2==7)  c[1][1]=c[25][25]=c[25][24]='X';
    cout<<"25 25"<<endl;
    for(int i=1;i<=25;i++){
        for(int j=1;j<=25;j++){
            cout<<c[i][j];
        }
        cout<<endl;
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        for(int i=1;i<=25;i++){
            for(int j=1;j<=25;j++){
                c[i][j]='.';
            }
        }
        cin>>s;
        if(s<25){
            deal1();
        }
        else  deal2();
    }
    return 0;
}

Permutation Counting

题意:这题有点cf的味道,给你一个长为n-1的01序列,表示的是1-n这n个数的某种排列,如果,那么第i个位置就是0,否则就是1,要求求出符合条件的构造情况有多少种?
思路:看了题解后还是一头雾水,怎么想到的这种的构造方法的?
图片说明
可能是目前能力还没达到那种高度吧,把题解先贴在这里,希望以后能回来搞懂。
代码:

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll res;
int a[5010];
ll dp[5010][5010];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<n;i++)  cin>>a[i];
    memset(dp,0,sizeof(dp));
    dp[1][1]=1;
    if(a[1]) dp[2][1]=1;
    else  dp[2][2]=1;
    for(int i=2;i<n;i++){
        if(a[i]){
            for(int j=i;j;j--){
                dp[i+1][j]=(dp[i+1][j+1]+dp[i][j])%mod;
            }
        }
        else{
            for(int j=2;j<=i+1;j++){
                dp[i+1][j]=(dp[i][j-1]+dp[i+1][j-1])%mod;
            }
        }
    }
    res=0;
    for(int i=1;i<=n;i++)  res=(res+dp[n][i])%mod;
    cout<<res<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

Task Scheduler

题意:最开始开的就是这道题目,我觉得这道题目才是签到题,但后面看榜的时候发现这道题目过的人不多,以为有什么大坑,在加上题目有点没搞懂什么意思。所以跑去开其他题了,后面队友又在开这道题我就没看了。。。
这题就是有n个任务,每个任务需要ti名工人去做,其中有m个工人,这m个工人之中又有k个工人是与这种任务无关的,(也就是只有m-k个工人派去做任务才有用)。然后要求求出n个任务的一种完成顺序,使得派遣工人的次数最少。题目保证工人的完成人数是够的,也就是肯定存在一种方案使得可以完成所有的工作。同时答案要保证序列的字典序最小。
思路:贪心。首先,我们先考虑k=0的情况,这种是有点难想到的,如果k=0的话,我们直接输出1-n即可,如果k!=0的话,我们为了选工人的时候能够提高完成任务的概率(有可能选了比较多的k个无关工人中的人),我们肯定是要确保在选人尽量选到有关的工人,所以我们只需要对每个任务所需要的工人的数量进行排序,从多到少进行分配即可。因为在分式当中,当分子比分母小的情况下,分母和分子减少相同数的情况下,分数的大小会变得更小。也就是越到后面,就难选到有关的工人,而你如果选的越多的话,就更难选到满足任务所需的工人了。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int val;
    int index;
}Node[110];
bool cmp(node a,node b){
    if(a.val!=b.val)  return a.val>b.val;
    return a.index<b.index;
}
void solve(){
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>Node[i].val;
        Node[i].index=i;
    }
    if(k) sort(Node+1,Node+1+n,cmp);
    for(int i=1;i<=n;i++){
        cout<<Node[i].index;
        if(i<n)  cout<<" ";
    } 
    cout<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}