1 条题解

  • 0
    @ 2025-8-24 23:04:09

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Hollow_knight_
    -Silk Song is a lie-

    搬运于2025-08-24 23:04:09,当前版本为作者最后更新于2024-10-22 16:54:23,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    尝试贪心地依次选择能放在当前最上面的卡片。即先选择最上面的卡片,然后次上层,次次上层......

    显然,卡片 ii 能放在最上面的条件是 [sai,jci,j]=0\sum [ s_{a_{i,j}}\neq c_{i,j} ] = 0

    于是记 fi=[sai,jci,j]f_i=\sum [ s_{a_{i,j}}\neq c_{i,j} ],并将所有 fi=0f_i=0 的卡片 ii 放到一个队列 qq 中。

    假设放置了第一张卡片 ii,并将 ii 放入答案队列 ansans 中,现在需要更新后面的卡片。

    具体地,若卡片 ii 覆盖了位置 jj,那么后面选择的卡片就不需要在乎位置 jj 上的字符是否正确,因为位置 jj 已经被卡片 ii 正确的字母覆盖了。

    那么可以提前对于所有字符串下标 rr 开一个桶 grg_r。输入时对于卡片 ww,若有 saw,jcw,js_{a_{w,j}}\neq c_{w,j},将 ww 放在桶 gaw,jg_{a_{w,j}} 中。

    此时遍历卡片 ii 覆盖的所有位置 jj,若位置 jj 被之前的卡片覆盖就跳过,否则遍历桶 gjg_j 内的每一个元素 ww,令 fwfw1f_w\leftarrow f_w-1

    若更新完有 fw=0f_w=0,那么将 ww 也放到队列 qq 中。

    同时记录指针 cntcnt 表示未被覆盖的下标个数,初始有 cnt=mcnt=m,每次覆盖一个新的位置就令 cntcnt1cnt\leftarrow cnt-1

    若存在某一时刻 cnt=0cnt=0,就将剩余未选择的卡片随意放入 ansans 中,然后遍历 ansans 中的元素输出。

    若存在某一时刻 cnt0cnt\neq 0 且队列 qq 为空,则输出无解。

    对于遍历每个位置,时间复杂度为 Θ(k)\Theta(\sum k)

    对于遍历所有 gig_i,由于每个位置 ii 只会被覆盖 11 次,那么时间复杂度也为 Θ(k)\Theta(\sum k)

    总时间复杂度 Θ(n+k)\Theta(n+\sum k),可以通过。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+15;
    int n,m,hd=1,tl,q[N],vist[N],visp[N],f[N];//vist[i]:卡片i是否被使用 visp[i]:位置i是否被覆盖
    vector<int>ans,p[N],g[N];//p[i]:卡片i覆盖的位置 g[i]:意义见题解 
    char c,s[N];
    int main(){
    	scanf("%d%d",&n,&m);
    	scanf("%s",s+1);
    	for(int k,j,i=1;i<=n;++i){
    		scanf("%d",&k);
    		while(k--){
    			scanf("%d %c",&j,&c);
    			p[i].push_back(j);
    			if(s[j]!=c)++f[i],g[j].push_back(i);//模拟
    		}
    		if(!f[i])q[++tl]=i;//模拟
    	}
    	int cnt=m;
    	for(int w;hd<=tl;){
    		ans.push_back(w=q[hd++]),vist[w]=true;//取出一个f值为0的卡片w
    		for(int i:p[w]){
    			if(visp[i]==true)continue;
    			--cnt,visp[i]=true;//遍历w覆盖的所有位置
    			for(int j:g[i]){
    				if(!--f[j])q[++tl]=j;//更新
    			}
    		}
    		if(!cnt){
    			for(int i=1;i<=n;++i){if(!vist[i])ans.push_back(i);}
    			for(int i:ans)printf("%d ",i);
    			return 0;
    		}
    	}
    	printf("-1");//(cnt!=0 && q.empty()==true)
    	return 0;
    }
    
    • 1

    信息

    ID
    8969
    时间
    1000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者