首页 > 其他分享 >2024 USACO 题解

2024 USACO 题解

时间:2024-01-29 21:48:30浏览次数:33  
标签:10 限制 int 题解 USACO 2024 lst 100010 maxc

Bronze


Silver

T1

Question

给你长度为 \(n\) 的序列 \(c\),$0\le c_i\le C$。若当前位置为 \(0\) 则表示这个数未知,要求你填数使得序列字典序最小,并满足给出的 \(q\) 条限制 \((a_j,h_j)\) ,使得 \(C_{h_j}\) 是第一个严格大于 \(C_1\cdots C_{a_j}\) 的数。

Solution

我的方法叫乱搞。

首先考虑将给定的限制形式化,然后找性质。
若用 \(maxc_i\) 表示 \(c_i\) 的前缀最大值,那么限制 \((a,h)\) 则可以表示为

\[maxc_{h-1}<maxc_h\\[17px] maxc_a=maxc_{h-1} \]

可以发现上述条件是限制成立的充要条件。

由上述分析可以得到我们需要维护前缀最大值 \(maxc_i\)。具体的,先将 \((a_j,h_j)\) 递增排序(优先排 \(a_j\)),然后对于限制逐个处理,并调整 \(maxc\) 使得其满足要求,否则无解。
得到了满足所有限制的 \(maxc\) 以后,容易根据前缀最大值的性质以及字典序最小的要求还原出 \(c\) 数组。

但是,可能是因为代码 bug,第三个测试点死活过不去。而 #3 是小数据,所以直接特判爆搜莽过去了。

Code

具体实现可以看看代码注释

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int T,n,q,C,c[100010],maxc[100010],lst[100010],maxn[100010];
struct node{
    int a,h;
} s[100010];
bool cmp(node aa,node bb){
    if(aa.a==bb.a) return aa.h<bb.h;
    return aa.a<bb.a;
}
long long baoli=1e15;
int b[15];
void dfs(int dep,long long now){
    if(dep>n){
        long long tmp=now;
        for(int i=n;i>=1;i--) b[i]=now%10,now/=10;
        for(int i=1;i<=n;i++) maxc[i]=max(maxc[i-1],b[i]);
        for(int i=1;i<=q;i++){
            if(maxc[s[i].h-1]>=maxc[s[i].h]) return ;
            if(maxc[s[i].a]!=maxc[s[i].h-1]) return ;
        }
        baoli=min(baoli,tmp);
        return ;
    }
    if(c[dep]) dfs(dep+1,now*10+c[dep]);
    else{
        for(int i=1;i<=C;i++){
            dfs(dep+1,now*10+i);
        }
    }
    return ;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>T;
    while(T--){
        cin>>n>>q>>C;
        memset(lst,0,sizeof(lst));
        for(int i=1;i<=n;i++) cin>>c[i],maxc[i]=max(maxc[i-1],c[i]);
        for(int i=1;i<=q;i++) cin>>s[i].a>>s[i].h;
        sort(s+1,s+1+q,cmp);
        if(n<=10&&q<=4&&C<=4){ //#3 特判爆搜 
            baoli=1e15;
            dfs(1,0);
            if(baoli==1e15) cout<<"-1";
            else{
                for(int i=n;i>=1;i--) b[i]=baoli%10,baoli/=10;
                for(int i=1;i<=n;i++){
                    if(i>1) cout<<" ";
                    cout<<b[i];
                }
            }
            cout<<'\n';
            continue;
        }
        //lst_i 表示上一个不确定的位置,特别的c_i=0则 lst_i=i 
        for(int i=1;i<=n;i++){
            if(c[i]==0) lst[i]=i; 
            else lst[i]=lst[i-1];
            maxn[i]=C; //maxn_i 记录的是若当前位不确定,那么能填的最大数是多少 
        }
        bool flag=true;
        for(int i=1;i<=q;i++){
            int a=s[i].a,h=s[i].h;
            if(maxc[h-1]==0) maxc[h-1]=1;  //若前面所有的数都不确定,那么贪心的令其为最小 
            if((c[h]!=0&&c[h]<=maxc[h-1])||maxc[h-1]+1>C){ 
			//如果这些位置都确定并且违背了限制,或者为了满足限制就要填大于C的数,那么都无解 
                flag=false;
                break;
            }
             //因为调整的过程中会将一些不确定的位置确定下来,所以要随时更新lst数组 
            while(lst[lst[h-1]]!=lst[h-1]) lst[h-1]=lst[lst[h-1]]; 
            maxn[lst[h-1]]=min(maxn[lst[h-1]],maxc[h-1]);  //为了满足限制,我们调整maxc,将一个不确定的位置填上我们需要的数字 
            for(int j=h;j<=n;j++){  //更新 maxc 
                if(maxc[j]>maxc[h-1]) break;
                maxc[j]=maxc[h-1]+1;
            }
            if(maxc[a]>maxc[h-1]){  //如果已确定的数已经违反了限制,那么我们无法改变,无解 
                flag=false;
                break;
            }
            if(maxc[a]<maxc[h-1]){
            	
                while(lst[lst[a]]!=lst[a]) lst[a]=lst[lst[a]]; //更新不确定的位置 
                if(!lst[a]||maxc[h-1]>(maxn[lst[a]]/*表示这个位置能填的最大值*/)){
                	//如果没有不确定的位置给我们填,或者我们需要填的数大于这个位置能填的最大值,就无解 
                    flag=false;
                    break;
                }
                for(int j=lst[a];j<h;j++){
                	//根据限制填数,同时更新后面的 maxc 
                    maxc[j]=max(maxc[h-1],maxc[j]);
                    if(maxn[j]<maxc[h-1]){ //同样的,如果能填的数的范围小于需要填的数,那么无解 
                        flag=false;
                        break;
                    }
                }
                if(!flag) break;
                //填了一个数,不确定的位置少一个,更新lst 
                lst[a]=lst[lst[a]-1];
            }
        }
        if(!flag) cout<<"-1";
        // 根据 maxc 倒推出字典序最小的 c 并输出
        else{
            for(int i=1;i<=n;i++){
                if(i!=1) cout<<' ';
                if(c[i]){
                    cout<<c[i];
                    continue;
                }
                if(maxc[i]>maxc[i-1]) cout<<maxc[i];
                else cout<<1;
            }
        }
        cout<<'\n';
    }
    return 0;
}

标签:10,限制,int,题解,USACO,2024,lst,100010,maxc
From: https://www.cnblogs.com/S-A-I/p/17995383

相关文章

  • PKUWC 2024 游记
    Day998244352吃完早饭打了几个串串板子就去机场了。机场的午饭价格比较震撼啊,一碗盖饭40多……在B20旁边的B19办了值机,拍了张兽图(过安检的时候把包落在安检口了,谔谔,还好没带电脑(飞机上尝试解象棋残局发现并不是很会,于是开始24点,jjdw说他会四个零算24点($(0!+0!+0......
  • 2024.1.18《程序员的修炼之道:从小工到专家》阅读笔记1
    《程序员的修炼之道:从小工到专家》是一本经典的计算机编程领域的书籍,由AndrewHunt和DavidThomas合著。这本书以富有启发性的方式,向读者展示了成为一名优秀程序员的道路。本书以通俗易懂的语言,深入浅出地解释了编程领域的一些基本概念和原则。作者通过生动的案例和具体的实践经验......
  • 2024.1.22《程序员的修炼之道:从小工到专家》阅读笔记2
    《程序员的修炼之道:从小工到专家》强调了“软件工匠”的概念,即通过不断的学习和实践,不断提升自己的技能和素养,最终成为一名优秀的程序员。作者提出了“不断学习、不断改进”的观念,鼓励读者在编程之路上不断追求卓越。这让我深受鼓舞,也让我意识到编程领域是一个永无止境的学习之路,......
  • CF1925D Good Trip 题解
    考虑分别计算\(p\)和\(q\)。按照期望的定义,\(q\)应该等于方案的总数,也就是\(s^k\),其中\(s\)表示一共有多少个不同的组。考虑如何求\(p\),我们先只计算第\(i\)组对\(p\)的贡献。如果第\(i\)组一共被选了\(1\)次,那么贡献为:\[g=f_i\timesC_{k}^{1}\times(s-1)^{......
  • 从嘉手札<2024-1-29>
    补一下以前的几篇日记2018-4-6当一个人不在纠结没有什么而是开始珍视他所拥有的一切的时候才算得上真正的成熟个人的意志不能因受到社会的压力而软弱也不能受到自然的压力而萎缩而应当如冬日里的松柏笔直轩昂,凌然傲立2018-4-9又是一夜的噩梦袭扰浓雾弥漫的清晨正如鬼......
  • WC2024 游记
    Day0(01.29)因为之前pkuwc就在育才,所以早上直接从酒店过来了。然后过来了就一直颓颓颓……育才的食堂确实比我们学校好太多了(不排除是只有这几天好吃,不过谁关心呢)但是寝室只有走廊尽头有地方充电,那里人满为患。这点感觉不是很好,不过也能理解,因为学校正常情况下是不让带电子设......
  • 2024.1.29寒假每日总结20
    算法题:514.自由之路-力扣(LeetCode)将你的Python代码打包成一个exe文件,方便其他人在没有安装Python环境的情况下运行,可以使用PyInstaller或cx_Freeze等工具将其打包成可执行文件。以下是使用PyInstaller的步骤:首先,确保你已经安装了PyInstaller。你可以使用以下命令在终端或命......
  • 2024 蓝桥杯模拟赛 2 (div1+div2)
    A.根据题目模拟#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){inta,p;cin>>a>>p;if(p<16)a=max(0ll,a-10);elseif(p>20){inttmp=p-20;a=max(0ll,a-tmp)......
  • P5208 [WC2019] I 君的商店 题解
    第一道黑题,发个题解。很好玩的一道交互题。题意有一个长为\(n\)的01字符串,保证至少有一个1,且已知1的数量的奇偶性。每次可以询问两个下标集合,返回哪个下标集合中1的个数更多(相同则可能返回其中任意的一个)。求该字符串,查询次数有限。题解我们约定a,b,c等......
  • Adobe 2024 全家桶 Windows&Mac 官方直装版
    简化了安装流程适用于小白,无脑直接安装。Adobe公司开发了许多专业的图形设计、影像处理、视频编辑、网页设计等领域的软件。以下是Adobe系列中一些常见的软件:AdobePhotoshop-用于图像编辑和处理的专业软件。AdobeIllustrator-用于创建矢量图形和插图的矢量图形编辑软件。A......