2023第一周训练

第一题 一个小整数

题面http://oj.daimayuan.top/problem/1002
思路,最开始想的是先找出最多的数和其他数总和,如果最多的数大,则必有相邻重复项,如果小,再先由小到大不重复的排,排完之后在倒序插入剩下的数,但后来发现如果 8,9 有很多,8会和7匹配,剩9,就变成78787878插9,就成了789789798,但很明显,正确答案应该是78787898989,
后来,改成了
我们的目的是每次选尽可能小且不重复的数,同时要保证有解,不能出现1212999这种情况,所以假设前面选的数符合题意,我们只要保证接下来的数最小就解出来了,sum为其他数总和,max为最多数的个数。

sum=0;

数选完了,返回1

sum+1=max

只有xyxyx这一种排法,所以只能选最多的那个数

sum+1>max

保证不重复的选一个最小的数就行了
最后0要单独拧出来,同时初始last=0,保证首项不为0;

#include<bits/stdc++.h>
using namespace std;
vector<int>ans;
int last=0;
int num[10];
bool dfs(){
    int sum=0;int maxx=0; int maxn=0;
    //maxx记录最大数的个数,maxn记录最大数
    for(int i=0;i<10;i++){
        if(num[i]>maxx){
            maxx=num[i];
            maxn=i;
        }
        sum+=num[i];
    }
    if(sum==0)return 1;
    sum-=maxx;
    if(sum+1<maxx){return 0;}
    if(sum+1==maxx){
        if(maxn==0&&ans.empty()){
            return 0;
        }
        ans.push_back(maxn);
        num[maxn]--;
        last=maxn;
    }else{
        for(int i=ans.size()==0?1:0;i<10;i++){
            if(i!=last&&num[i]){
                ans.push_back(i);
                num[i]--;
                last=i;
                break;
            }
        }
    }
    return dfs();
}
int main(){
    int sum=0;
    for(int i=0;i<10;i++){
        cin>>num[i];
        sum+=num[i];
    }
    if(sum==1&&num[0]){
        cout<<0;
        return 0;
    }
    if(dfs()){
        if(ans.size()==0){
            cout<<-1;
        }else{
                for(auto a:ans){
        cout<<a;
    }
        }
    }else{
        cout<<-1;
    }

    //cout<<endl;
    // for(auto x:num){
    //     cout<<x<<endl;
    // }
}

第二题 特殊的正方形

题面http://oj.daimayuan.top/course/11/problem/386
由正方形,所以我们只要排出左上角的一小块就行了,之后在根据奇偶镜像打印输出
对于每一个点,若他上和左的一样,则这个点和这两不一样
若上和左不一样,但上和左上一样,则他和左一样
若上和左不一样,但左和左上一样,则他和上一样

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    bool ans[55][110]={0};
    int main(){
        cin>>n;
        for(int i=0;i<n/2+1;i++){
            for(int j=0;j<n;j++){
                if(i==0){
                    ans[i][j]=1;
                    continue;
                }
                if(j==0){
                    ans[i][j]=1;
                    continue;
                }
                if(ans[i-1][j]==ans[i][j-1]){
                    ans[i][j]=(!ans[i][j-1]);
                }else if(ans[i-1][j-1]==ans[i-1][j]){
                    ans[i][j]=ans[i][j-1];
                }else{
                    ans[i][j]=ans[i-1][j];
                }
            }
        }
        // for(int i=0;i<n/2+1;i++){
        //     for(int j=0;j<n;j++){
        //         cout<<ans[i][j];
        //     }
        //     cout<<endl;
        // }
        if(n%2==0){
            for(int i=0;i<n/2;i++){
                for(int j=0;j<n/2;j++){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                for(int j=n/2-1;j>=0;j--){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                cout<<endl;
            }
            for(int i=n/2-1;i>=0;i--){
                for(int j=0;j<n/2;j++){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                for(int j=n/2-1;j>=0;j--){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                cout<<endl;
            }
        }else{
            for(int i=0;i<n/2+1;i++){
                for(int j=0;j<n/2+1;j++){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                for(int j=n/2-1;j>=0;j--){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                cout<<endl;
            }
            for(int i=n/2-1;i>=0;i--){
                for(int j=0;j<n/2+1;j++){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                for(int j=n/2-1;j>=0;j--){
                    if(ans[i][j]){
                        cout<<"+";
                    }else{
                        cout<<".";
                    }
                }
                cout<<endl;
            }
        }
    }

第三题 走楼梯2

题面http://oj.daimayuan.top/course/11/problem/129
最开始想的是dp,就第n阶等于n-1的情况跨一步和n-2的跨两步,之后以为n-2只有一种情况会到n-2有连跨两次两步,就只减了1,后面发现远不止一种情况
对于第n个台阶,两种跳法,1,从n-1跳一步,2从n-2跳两步,但要排除掉连跳三次的,3,从n-6开始可以连跳三次到n,但不是所有n-6的情况都能连跳,只有跳一步到n-6的才能连跳,所以减掉n-7就行了
最后发现45都能过,50过不了,调了半天发现,没开longlong。。。。。

    #include<bits/stdc++.h>
    using namespace std;
    long long ans[55];
    int n;
    int main(){
        cin>>n;
        ans[0]=1;
        ans[1]=2;
        ans[2]=3;
        ans[3]=5;
        ans[4]=8;
        ans[5]=12;
        ans[6]=19;
        ans[7]=30;
        if(n<7){
            cout<<ans[n-1]; 
            return 0;
        };
        for(int i=8;i<n;i++){
            ans[i]=ans[i-1]+ans[i-2]-ans[i-7];
        }
        cout<<ans[n-1];
        return 0;
    }

第四题

题面http://oj.daimayuan.top/course/11/problem/460
第一次用dfs写,不出意外的TLE了,于是转成动规
dp[i][j]表示第i行的第j位置能不能跑到
于是 dp[i][j]=(dp[i-1][j-ori[i][0]]||dp[i-1][j-ori[i][1]]);
然后第一行在手输一下就完事

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int dp[110][maxn]={0};
    int ori[110][2];
    int n,m;
    int main(){
	    ios::sync_with_stdio(false);
	    cin.tie(0);
        cout.tie(0);
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>ori[i][0];
            cin>>ori[i][1];
        }
        dp[1][ori[1][0]]=1;
        dp[1][ori[1][1]]=1;
        for(int i=2;i<=n;i++){
            for(int j=0;j<=m;j++){
                dp[i][j]=(dp[i-1][j-ori[i][0]]||dp[i-1][j-ori[i][1]]);
            }
        }
        for(int i=0;i<=m;i++){
            cout<<dp[n][i];
        }
    }

第五题 简单分数统计

题面:http://oj.daimayuan.top/problem/455
很水的水题,,,,用map优化了一下,感觉写的还是不行,也许能优化,但,没必要,哎嘿。

#include <bits/stdc++.h>
using namespace std;
int main() {
	map<string, int>ori;
	int n, m, k;
	cin >> n >> m >> k;
	string name1[210];
	for (int i = 1; i <= n; i++) {
		string a;
		cin >> a;
		ori[a] = i;
		name1[i] = a;
	}
	map<string, int > ti;
	for (int i = 0; i < m; i++) {
		string temp;
		int temp1;
		cin >> temp >> temp1;
		ti[temp] = temp1;
	}
	int score[210] = { 0 };
	for (int i = 0; i < k; i++) {
		string name, timu, pass;
		cin >> name >> timu >> pass;
		if (pass == "WA")continue;
		if (ori[name] == 0)continue;
		score[ori[name]] += ti[timu];
	}
	for (int i = 1; i <= n; i++) {
		cout << name1[i] << " " << score[i] << endl;
	}
}

第六题 Alice的德州扑克

题面:http://oj.daimayuan.top/problem/453
水题+1

#include<bits/stdc++.h>
using namespace std;
struct pai
{
    int dian;
    int hua;
};
pai ori[5];
int dian[15];
int main(){
    for(int i=0;i<5;i++){
        cin>>ori[i].dian;
        dian[ori[i].dian]++;
    }
    for(int i=0;i<5;i++){
        cin>>ori[i].hua;
    }
    bool shun=1;
    for(int i=1;i<5;i++){
        if(ori[i].dian!=(ori[i-1].dian+1)){
            shun=0;
            break;
        }
    }
    bool tong =1;
    for(int i=1;i<5;i++){
        if(ori[i].hua!=ori[i-1].hua){
            tong=0;
            break;
        }
    }
    if(shun==1&&tong==1&&ori[4].dian==14){
        cout<<"ROYAL FLUSH"<<endl;
        return 0;
    }
    if(shun==1&&tong==1){
        cout<<"STRAIGHT FLUSH"<<endl;
        return 0;
    }
    for(int i=1;i<=14;i++){
        if(dian[i]>=4){
            cout<< "FOUR OF A KIND"<<endl;
            return 0;
        }
    }
    int fullhouse1=0;
    int fullhouse2=0;
    for(int i=1;i<=14;i++){
        if(dian[i]>=3){
            fullhouse1++;
        }
        if(dian[i]==2){
            fullhouse2++;
        } 
    }
    if(fullhouse1==1&&fullhouse2==1){
        cout<<"FULL HOUSE"<<endl;
        return 0;
    }
    if(tong==1){
        cout<< "FLUSH"<<endl;
        return 0;
    }
    if(shun==1){
        cout<<"STRAIGHT"<<endl;
        return 0;
    }
    cout<<"FOLD"<<endl;
}

第七题 订单编号

题面:http://oj.daimayuan.top/problem/465
最开始写了个dp优化的累加,若有相同的数则从dp里面找最大,但还是卡了一个点,最后改成:
用set存所有有空位的区间,当处理一个数x的时候,找到离他最近的右端比他大的区间,如果找左端的话会出现区间[4,6],[8,10];找6,会返回[8,10],而我们要找的是[4,6],之后根据找到的区间的左端选择输出x还是右端,输出完后更新区间即可
一些细节写在注释里了
由于是查的区间,效率会比dp的一个数一个数的找快

#include<bits/stdc++.h>
using namespace std;
set<pair<int,int>> qujian;
//pair 第一个为右端,第二个为左端
void join(int r,int l){
    if(l>r)return;
    qujian.insert({r,l});
    //second x-1 x x+1 first
    //x+1有可能比first大,同理x-1所以要判断
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    qujian.insert({2e9,1});
    int x;
    for(int i=0;i<n;i++){
        cin>>x;
        auto it=qujian.lower_bound({x,0});
        //查找比[0,x]右端大的第一个区间,因为小于x的区间都用不了
        //second是左,first是右端
        if(x>=it->second){

            cout<<x<<" ";
            join(it->first,x+1);
            join(x-1,it->second);
            qujian.erase(it);
            //左端小于x,输出x
            //second x-1 x x+1 first
        }else{
            cout<<it->second<<" ";
            join(it->first,it->second+1);
            qujian.erase(it);
            //左端大于x,输出左端
        }
        //cout<<0;
    }
}

第八题463. 饿饿 饭饭

用优先队列存饭量,每次喂给所有人饭量最小的分量,也就是喂了最小分量的轮数,同时k减少轮数*人数,当不能在喂一轮后,start=k%人数,之后从start开始,判断能不能喂饱,能就跳过

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
struct ren {
    int fan;
    int id;
    friend bool operator < (ren a, ren b) {
        return a.fan > b.fan;
    }
};
int ori[maxn];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n;
    long long k;
    cin >> n >> k;
    priority_queue<ren> shu;
    long long sum = 0;
    for (int i = 1; i <= n; i++) {
        ren temp;
        cin>>temp.fan;
        //temp.fan = i;
        temp.id = i;
        shu.push(temp);
        sum += temp.fan;
        ori[i] = temp.fan;
    }
    if (sum < k) {
        cout << -1;
        return 0;
    }
    if (sum == k) {
        return 0;
    }
    ren top;
    int lun = 0;
    int start;
    int last;
    while (!shu.empty())
    {
        top = shu.top();
        if (k <(shu.size() * (top.fan-lun))) {
            //不满足再打一轮
            start=k%shu.size();
            last=(k-start)/shu.size();
            break;
        }
        lun+=top.fan;
        k -= shu.size()*lun;
 
        //cout << lun << endl;
        while (top.fan == shu.top().fan)
        {
            shu.pop();
        }
    }
    int ans[maxn];
    int answei = 0;
    while (!shu.empty())
    {
        ren temp;
        temp = shu.top();
        shu.pop();
        ans[answei++] = temp.id;

    }
    sort(ans, ans + answei);
    
    for (int i = start; i < answei; i++) {
        //最后一轮没吃到饭的
        cout << ans[i] << " ";
    }
    for (int i = 0; i < start; i++) {
        if (ori[ans[i]] == lun + last+1)continue;
        cout << ans[i] << " ";
    }
    return 0;
}

第九题 任务分配

题面 http://oj.daimayuan.top/course/11/problem/461
第一种,纯纯暴力
dp[i]代表i时的最大值
每一个时刻都转一遍所有计划,如果有计划的起始等于i,更新计划的终点,终点等于终点原先的时刻价值和起始点加价值后两者的最大值,
两个细节
1,只有时刻过了终点后最大值才会更新
2,下一个时刻等于这一个时刻的和下一个时刻取最大,因为下一个时刻可能有哪个计划的终点落那了
第二种,另一个思路的dp,还在调,,,,,,

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
long long dp[maxn];
struct one{
    int s;
    int e;
    int w;
};
one ori[maxn];
bool cmp(one a,one b){
    return a.s>b.s;
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>ori[i].s>>ori[i].e>>ori[i].w;
    }
    for(int i=1;i<=1000;i++){
        dp[i+1]=max(dp[i],dp[i+1]);
        for(int j=1;j<=n;j++){
            if(i==ori[j].s){
                dp[ori[j].e]=max(dp[i]+ori[j].w,dp[ori[j].e]);
            }
        }
    }
    cout<<dp[1000];
}

第十题 路径计数

题面:http://oj.daimayuan.top/problem/126
一开始想的直接暴力dfs,不过看了眼方案数要mod,dfs肯定超时了,然后根据dfs不行就试dp的思路,还真想到一个,dp[i][j]=dp[i-1][j]+dp[i][j-1],每一个点只可能从上面或左边过来,那直接把两边的方案数相加就得到当前点的方案数。

#include<bits/stdc++.h>
using namespace std;
long long mod=1e9+7;
int ori[110][110];
int n;
long long ans[110][110]={0};
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>ori[i][j];
        }
    }
    ans[0][1]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(ori[i][j]==0)continue;
            ans[i][j]=(ans[i][j-1]+ans[i-1][j])%mod;
        }
    }
    cout<<ans[n][n];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值