首页 > 其他分享 >2023年暑假集训总结/6.29

2023年暑假集训总结/6.29

时间:2023-07-02 20:22:05浏览次数:35  
标签:std nxt vis int ai vec 2023 集训 6.29

6-27

T1有毒爱排列

  有毒让你求长度为 n 且逆序对个数对 p 取余为 k 的排列的个数,答案对 998244353取模。

  考试时我考虑到设 fi,j 表示放了数 1 ∼ i,此时逆序对个数 mod p = j 的排列个数。转移显然,枚举 i + 1 放到哪个位置即可,时间复杂度 O(n^2p)。得了60分,而后通过观察性质可以发现n>p时答案就是 n!/p,那么可以把 n 压到 100,时间复杂度 O(p^3 )。

  std:

  

#include<bits/stdc++.h>
using namespace std;
#define int long long
int const N=1e4+10;
int const K=100+5;
int const mod=998244353;
int f[N][K],nw[K],w[K],n,p,k;
signed main(){
    freopen("per.in","r",stdin);
    freopen("per.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>p>>k;
    if (n>p){
    int g=1;
    for (int i=1;i<=n;++i)
        if (i!=p) g*=i,g%=mod;
    cout<<g<<'\n';
        return 0;
    }
    f[1][0]=1,++nw[1%p];
    for (int i=2;i<=n;++i){
        ++nw[i%p];
        for (int j=0;j<p;++j){
            int q=(i%p-j+p)%p;
            w[j]=nw[q];
        }
        for (int la=0;la<p;++la)
            for (int ni=0;ni<p;++ni)
                f[i][(la+ni)%p]+=f[i-1][la]*w[ni]%mod,f[i][(la+ni)%p]%=mod;
    }
    cout<<f[n][k]<<'\n';
    return 0;
}

 

T2有毒爱 AT

  有毒得到了一个字符串,这个字符串上的每一个字符都代表着某题在某场 agc 中的题目编号(例如:FEABCDD)。我们定义吊打子序列为 ABCDE 或 ABCDEF。有毒会询问多次,每次有毒会询问一个区间 [li , ri ],设字符串 t 为 sli,...,ri。你需要回答 t 最多能划分成几个不相交的吊打子序列。

  直接n^2可拿45分,考虑优化这个匹配过程,我们从右往左枚举每个左端点,依然是考虑贪心匹配,我们考虑后缀 i → 后缀 i − 1 会改变哪些东西。往开头增加一个字母等价于从这个字母开始往后贪心匹配最靠前的且能匹配的字母。所以我们开个 set 维护一下每种字符出现的位置即可。

  std:

//A tree without skin will surely die.
//A man without face is invincible.
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-x)
int const N=5e5+10;
int ans[N];set<int>s[6];
vector< pair<int,int> >a[N];
struct Tree_Array{
    int c[N];
    void update(int x,int v){while (x<N) c[x]+=v,x+=lowbit(x);}
    int query(int x){int res=0;while (x) res+=c[x],x-=lowbit(x);return res;}
}T;
signed main(){
    freopen("agc.in","r",stdin);
    freopen("agc.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int n,q;cin>>n;
    string t;cin>>t>>q,t=" "+t;
    for (int i=1;i<=q;++i){
        int l,r;cin>>l>>r;
        a[l].push_back({r,i});
    }
    for (int i=n;i>=1;--i){
        if (t[i]!='A') s[t[i]-'A'].insert(i);
        else{
            int y=i,flg=1;
            for (int j=1;j<5;++j)
                if (s[j].lower_bound(y)!=s[j].end()) y=*s[j].lower_bound(y);
                else{flg=0;break;}
            if (flg){
                y=i;
                for (int j=1;j<5;++j){
                    int p=*s[j].lower_bound(y);
                    s[j].erase(s[j].lower_bound(y)),y=p;
                }
                T.update(y,1);
            }else s[t[i]-'A'].insert(i);
        }
        for (auto g:a[i]){
            int r=g.first,id=g.second;
            ans[id]=T.query(r);
        }
    }
    for (int i=1;i<=q;++i) cout<<ans[i]<<'\n';
    return 0;
}

 

T3妈妈生的

  鱼给了你一个 1 ∼ n 的排列 a。

  我们定义一次操作为执行以下两种函数之一:

  • 执行一次 f(),这需要 x 的代价。

  • 选择一个整数 b (1 ≤ b ≤ n),然后执行 s(b),这需要 y 的代价。

  当 a 满足 ∀i (1 ≤ i ≤ n), ai = i 时,停止操作,否则继续进行下一次操作。你需要令停止操作时花费的代价最少,并输出这个最少代价。如不理解题意可以看样例解释。两种函数代码如下:

  

void f(){
  for (int i=1;i<=n;++i)
  if (a[i]<i) swap(a[i],a[a[i]]);
 }

  

void s(int x){
  vector<int>b;map<int,int>vis;
  while (!vis[x]) vis[x]=1,b.push_back(x),x=a[x];
  sort(b.begin(),b.end());
  reverse(b.begin(),b.end());
  for (int i=0;i<b.size();++i) a[b[i]]=b[(i+1)%b.size()];
 }

  考虑观察 f() 函数和 s(x) 函数本质是什么。一个 swap(ai , aai ) 相当于在置换环上把 ai 删掉,令 ai 变成自环,然后 ai 左边那个数连向 ai 右边那个数。所以每个置换环都是独立的。如果我们仅仅用 f() 函数,那么操作次数就是所有置换环需要 f() 次数的 max。我们继续思考 f() 函数的本质,发现对于一个点 i,如果点 i 左边的点的权值比它大,那么它会被删掉。我们用链表维护当前置换环内的数,删掉一个数就判一下它的 next 是否满足条件。由于每个数只会被删一次,复杂度是对的。时间复杂度 O(n log n),瓶颈在于排序。

  std:

//A tree without skin will surely die.
//A man without face is invincible.
#include<bits/stdc++.h>
using namespace std;
#define int long long
int const N=1e6+10;
int a[N],vis[N],f[N],ct,pre[N],del[N],nxt[N],suf[N];
vector<int>s,vec;
void d(int x){
    nxt[pre[x]]=nxt[x],pre[nxt[x]]=pre[x];
    if (!del[nxt[x]] && (vec[pre[x]]>vec[nxt[x]])) s.push_back(nxt[x]);
}
signed main(){
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int n,x,y;cin>>n>>x>>y;
    for (int i=1;i<=n;++i) cin>>a[i];
    for (int i=1;i<=n;++i){
        if (vis[i]) continue;
        int y=i;vec.clear();vector<int>v;ct=0;
        while (!vis[y]) vec.push_back(y),vis[y]=1,y=a[y];
        for (int i=1;i<vec.size();++i) pre[i]=i-1;pre[0]=vec.size()-1;
        for (int i=0;i<vec.size()-1;++i) nxt[i]=i+1;nxt[vec.size()-1]=0;
        for (int i=0;i<vec.size();++i) del[i]=0;
        for (int i=0;i<vec.size();++i) if (vec[pre[i]]>vec[i]) v.push_back(i);
        if (vec.size()==1) continue;
        int lun=0;
        while (1){
            ++lun;for (auto i:v) ++ct,del[i]=1;
            if (ct==vec.size()-1) break;
            s.clear();for (auto i:v) d(i);
            sort(s.begin(),s.end());
            s.erase(unique(s.begin(),s.end()),s.end());
            v=s;
        }
        f[++f[0]]=lun;
        for (auto i:vec) vis[i]=1;
    }
    sort(f+1,f+f[0]+1,[](int x,int y){return x>y;});
    int ans=1e18;f[++f[0]]=1;
    for (int i=f[0];i;--i) suf[i]=suf[i+1]+f[i];
    for (int i=1;i<=f[0];++i) ans=min(ans,(i-1)*y+f[i]*x);
    cout<<ans<<'\n';
    return 0;
}

 

标签:std,nxt,vis,int,ai,vec,2023,集训,6.29
From: https://www.cnblogs.com/determination/p/17521314.html

相关文章

  • 2023年暑假集训总结/6.27
    6-27T1图一姬在一个n个点和m条边无向图中迷路了,她不知道她现在在哪里。每个点上有一个宝玉,一姬要收集k个宝玉才能缔结契约,走出这个无向图。图中被访问的点不能再访问第二次,经过每条边需要一定的时间,求所需的最大时间是多少?注:走到的点宝玉必须要取走。收集到k个宝......
  • P9381 [THUPC 2023 决赛] 那些脑海里最珍贵的
    小清新大模拟(?写起来挺顺的,就是浮点误差那块整破防了,最后问了神虎用了科学计数法存浮点数才过stO神虎Orz坑点:注意精度误差死亡后要清除Average的主动技能,防止重复触发死亡处理导致被动技能被弄乱Average的主动技能里的“\(3\)个回合”指的是南北两边各行动一次算一......
  • 2023年暑假集训总结/6.26
    6-26T1粉丝问我ctrl键在哪里励志阿伟现在正处在一个冰火迷宫中,迷宫由n个格子组成,每个格子要么是冰之格,要么是火之格,励志阿伟刚开始可以选择从迷宫中任意一个开始走,走到第i个位置时会得到值为ai的积分。如果励志阿伟当前在冰之格,那么他可以选择一个编号大于当前格子的......
  • 2023 冲刺国赛自测 9
    轻度的断食似乎对精神状态有好处。不过相比两年前还是吃的多些。两年前今天中午吃的一点东西是我当时一天的量。T3我会60的部分分,但是没写。问就是正解忘了板子怎么打。不如直接脖子右拧。晚上又没吃饭,感觉精神状态好了一些。明天早上得吃了,再不吃按照经验我妈得找我了。但......
  • C/C++职员薪资查询系统[2023-07-02]
    C/C++职员薪资查询系统[2023-07-02]数据结构与算法程序设计职员薪资查询系统1项目要求项目名称 职员薪资查询系统 项目类型 应用软件类项目难度 中等 素材资源 无(../res)使用工具 不限 编译系统 Windows、Linux硬件需求 无 程序语言 不限知识点 结构体/类、树、图、链表、......
  • 2023/7/2
    今天学习了两种类型转换,首先是向上转型,就是用父类的对象来引用子类,这种转型是安全的,注意父类的对象不能访问子类中的属性和方法。然后是向下转型,这种转型是不安全的,父类对象不能直接赋值给子类对象,要实现向下转型需要借助强制类型转换:子类类型子类对象=(子类类型)父类对象。......
  • 2023.26 工程化思维
    工程化思维是一种解决问题和实现目标的思考方式,它强调系统性、结构化和分析性。工程化思维要求人们以科学的方法去分析问题、评估方案,并采取有序、可衡量的步骤来实现目标。在技术领域,工程化思维尤为重要,因为它有助于提高工作效率和项目的成功率。这周在处理一个项目问题时意识到......
  • C/C++订餐管理系统[2023-07-02]
    C/C++订餐管理系统[2023-07-02]1、订餐管理系统要求实现饭店的订餐信息管理,包括菜单管理、订单管理、统计分析。实现菜单信息(菜号、菜名、价格、成本)的增删改查,实现订单管理(订单号、就餐人数、下单时间、订单总价、订单包含的所有菜品(菜号、数量))。系统功能包括以下方......
  • Excel基础_2023/7/2
    典型函数=SUM()=AVERAGE()=IF(条件,命令1,命令2)相对引用(默认),绝对引用(加$在对应行/列)单元格统计函数COUNTCOUNTACOUNTBLANKCOUNTIF(区域,要记录的标准)/COUNTIFS推荐对不熟的函数使用参数面板。比较符号:><>=<=<>文本查找-通配符:?代表一个字,*代表有内容(但被两个......
  • Excel基础_2023/7/1
    清洗数据网上爬取时,选择合适区域再excel处理,用PowerQuery可以:更改筛选标题、筛选合适项、删除异常项,然后导入新表格区域。简单改变单元格格式关于边框,可以调整颜色,也可以设置网格线(打印时网格线则需另选)可通过格式-其他格式进行设置有符号、颜色选项'+内容可使内容变文......