首页 > 其他分享 >省选联测 42

省选联测 42

时间:2023-02-28 15:58:02浏览次数:40  
标签:head 省选 42 int edge 联测 100010 fac include

又垫底了。不懂为什么 T3 都切了。鉴定为人菜。

joke3579 说他演了一整场,那他比较强。

猜数字

思博题。位数是 \(n\lg n+1\)。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int n;
char s[300010];
int main(){
    scanf("%s",s+1);n=strlen(s+1);
    if(n==1){
        if(s[1]=='1')puts("1");
        else puts("2");
        return 0;
    }
    for(int i=3;i<=50000;i++){
        if((int)(i*log10(i)+1)==n){
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}

吵架

原题。ZJOI 捉迷藏。就是线段树找直径。

赛时一开始调了半天点分树。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int n,q;
struct gra{
    int v,next;
}edge[200010];
int t,head[100010];
void add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int size[100010],top[100010],dep[100010],son[100010],fa[100010];
void dfs1(int x,int f){
    size[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f){
            dfs1(edge[i].v,x);
            size[x]+=size[edge[i].v];
            if(size[son[x]]<size[edge[i].v])son[x]=edge[i].v;
        }
    }
}
void dfs2(int x,int f,int tp){
    top[x]=tp;
    if(son[x])dfs2(son[x],x,tp);
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=f&&edge[i].v!=son[x])dfs2(edge[i].v,x,edge[i].v);
    }
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}
int dis(int x,int y){
    if(!x||!y)return -1;
    return dep[x]+dep[y]-2*dep[lca(x,y)];
}
int col[100010];
#define lson rt<<1
#define rson rt<<1|1
struct stu{
    int d,x,y;
    friend stu operator+(const stu&s,const stu&t){
        if(s.d==0&&t.d==0)return {dis(s.x,t.x),s.x,t.x};
        else if(s.d==-1)return t;
        else if(t.d==-1)return s;
        stu ans={0,0,0};
        if(ans.d<s.d)ans=s;
        if(ans.d<t.d)ans=t;
        int d=dis(s.x,t.x);
        if(ans.d<d)ans={d,s.x,t.x};
        d=dis(s.x,t.y);
        if(ans.d<d)ans={d,s.x,t.y};
        d=dis(s.y,t.x);
        if(ans.d<d)ans={d,s.y,t.x};
        d=dis(s.y,t.y);
        if(ans.d<d)ans={d,s.y,t.y};
        return ans;
    }
}tree[400010];
void build(int rt,int l,int r){
    if(l==r){
        col[l]=true;tree[rt]={0,l,0};return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    tree[rt]=tree[lson]+tree[rson];
}
void update(int rt,int L,int R,int pos){
    if(L==R){
        if(col[pos])tree[rt]={-1,0,0},col[pos]=false;
        else tree[rt]={0,pos,0},col[pos]=true;
        return;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)update(lson,L,mid,pos);
    else update(rson,mid+1,R,pos);
    tree[rt]=tree[lson]+tree[rson];
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        add(u,v);add(v,u);
    }
    dfs1(1,0);dfs2(1,0,1);
    build(1,1,n);
    cin>>q;
    while(q--){
        char od[5];cin>>od;
        if(od[0]=='C'){
            int x;cin>>x;update(1,1,n,x);
        }
        else cout<<tree[1].d<<'\n';
    }
    return 0;
}

选数游戏 V2

赛时冲了一发 floyd。

首先特判一堆东西。然后问题变成每个数二进制位 \(1\) 或 \(2\) 个 \(1\),找最少的数使得异或和为 \(0\)。然后对于两个 \(1\) 的在它们之间连边,对于一个 \(1\) 的新建个虚点 \(0\) 连边,就变成了最小环。显然不能 floyd,是 \(O(n^3)\)。暴力枚举每个点为起点也是 \(O(n^2)\)。

发现每个环一定经过小于 \(1000\) 的质因数,于是只需要扫这些点作为起点,就可以过了。复杂度 \(O(n\pi(\sqrt n))\)。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
int n,fac[10],ans=0x3f3f3f3f;
struct node{
    int v,next;
}edge[200010];
int t,head[1000010];
void add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
int p[1010];
bool v[1010];
void get(int n=1000){
    for(int i=2;i<=n;i++){
        if(!v[i])p[++p[0]]=i;
        for(int j=1;j<=p[0]&&i*p[j]<=n;j++){
            v[i*p[j]]=true;
            if(i%p[j]==0)break;
        }
    }
}
int dis[1000010];
bool vis[1000010];
void bfs(int st){
    queue<int>q;
    for(int i=1;i<=1000000;i++)dis[i]=0x3f3f3f3f,vis[i]=false;
    dis[st]=0;q.push(st);
    while(!q.empty()){
        int x=q.front();q.pop();vis[x]=true;
        for(int i=head[x];i;i=edge[i].next){
            if(vis[edge[i].v])continue;
            if(dis[edge[i].v]==0x3f3f3f3f){
                dis[edge[i].v]=dis[x]+1,q.push(edge[i].v);
            }
            else ans=min(ans,dis[x]+dis[edge[i].v]+1);
        }
    }
}
int main(){
    scanf("%d",&n);get();
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(x==1){
            puts("1");return 0;
        }
        fac[0]=0;fac[2]=1;
        for(int j=2;j*j<=x;j++){
            int cnt=0;
            while(x%j==0)cnt++,x/=j;
            if(cnt&1)fac[++fac[0]]=j;
        }
        if(x>1)fac[++fac[0]]=x;
        add(fac[1],fac[2]);add(fac[2],fac[1]);
    }
    for(int i=1;i<=p[0];i++)bfs(p[i]);
    if(ans==0x3f3f3f3f)ans=-1;
    printf("%d\n",ans);
}

nnntxdy

无数学。差评。不过 dp 真的好玄妙。我果然永远不会 dp。

首先看着这个 \(n\) 就很状压。那么设 \(dp_{i,S}\) 为克苏恩射 \(i\) 发还剩下 \(S\) 内的活着的概率。考虑转移,两种情况:

  1. 第 \(i\) 发射死一个:首先能分配的总伤害是射了 \(i-1\) 发减去射死的总血量,需要的伤害是这个随从的血量 \(-1\),是个组合数。不要忘记乘 \(1/\) 活着的随从数量。
  2. 没射死:需要能分配的伤害能够给每个随从留下最少一滴血。也要乘 \(1/\) 活着的随从数量。

然后考虑如何计算答案。对于活着的集合 \(s\),贡献是显然的,看看怎么算概率。由于我们还没有分配没射死随从的伤害,要考虑一下这些方案。那么分别扫每个活着的随从,乘若干组合数即可。具体的,设个 \(cnt_i\) 为还剩下 \(i\) 点伤害没分配的方案数,要的就是 \(cnt_0\)。枚举每个活着的随从受到多少伤害,每次乘组合数。

反正你要是让我再做一遍我也不会。qnmddp。

(克苏恩为什么不打脸)(算了反正炉石似了)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int mod=998244353;
int n,m,ans,a[20],C[210][210],dp[210][1<<15],inv[210],cnt[210];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    inv[1]=1;
    for(int i=2;i<=200;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=0;i<=200;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    dp[0][(1<<n)-1]=1;
    for(int i=0;i<m;i++){
        for(int s=1;s<(1<<n);s++){
            if(!dp[i][s])continue;
            int ret=i,sum=0;
            for(int j=1;j<=n;j++){
                if((s>>j-1)&1)sum+=a[j];
                else ret-=a[j];
            }
            for(int j=1;j<=n;j++){
                if(((s>>j-1)&1)&&ret>=a[j]-1)dp[i+1][s^(1<<j-1)]=(dp[i+1][s^(1<<j-1)]+1ll*dp[i][s]*inv[__builtin_popcount(s)]%mod*C[ret][a[j]-1])%mod;
            }
            if(ret<sum-__builtin_popcount(s))dp[i+1][s]=(dp[i+1][s]+1ll*dp[i][s]*inv[__builtin_popcount(s)])%mod;
        }
    }
    for(int s=0;s<(1<<n);s++){
        if(!dp[m][s])continue;
        int ret=m,sum=0;
        for(int i=1;i<=n;i++){
            if((s>>i-1)&1)sum+=a[i];
            else ret-=a[i];
        }
        cnt[ret]=1;
        for(int i=0;i<ret;i++)cnt[i]=0;
        for(int i=1;i<=n;i++){
            if(!((s>>i-1)&1))continue;
            for(int j=1;j<=ret;j++){
                for(int k=1;k<=min(a[i]-1,j);k++)cnt[j-k]=(cnt[j-k]+1ll*cnt[j]*C[j][k])%mod;
            }
        }
        ans=(ans+1ll*(n-__builtin_popcount(s))*dp[m][s]%mod*cnt[0])%mod;
    }
    printf("%d\n",ans);
    return 0;
}

标签:head,省选,42,int,edge,联测,100010,fac,include
From: https://www.cnblogs.com/gtm1514/p/17164557.html

相关文章

  • 2021 联合省选 A 卷题解
    比2022小清新了许多。卡牌游戏首先可以知道的是按照\(a\)升序排序,肯定有一段区间的\(a\)全保留,然后剩下的全翻面。那么我们需要求出最长的这段区间是什么。首先......
  • 一本通1424: 区间覆盖
    给一些区间,挑出最少的区间覆盖【0,L】  贪心:从0往后,每次挑出R点最大的#include<iostream>#include<algorithm>#include<cstring>#include<cmath>usingnam......
  • 2023 省选联测41 - ?
    2023省选联测41A.冤家路窄找出\(Deg\)用总路径数减去相遇的路径数code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;typedefunsigne......
  • 2021cspj省选
    1.#include<bits/stdc++.h>usingnamespacestd;vector<string>split(strings,charch){intstart=0;intlen=0;vector<string>ret;for(inti=0;i<s.len......
  • P8421 [THUPC2022 决赛] rsraogps
    \(\text{Solution}\)肯定扫描线在考虑维护什么东西,假设\(r\)右移时可以暴力得到所有新值,发现需要维护区间历史版本和以及区间当前值之和这三个操作对于一个数来说变化......
  • 242. 有效的字母异位词
    1classSolution{2public:3boolisAnagram(strings,stringt){4if(s.size()!=t.size())returnfalse;5string::iterators_it......
  • 省选联测37-40
    省选联测40后浪总结:典中典之注意到只有一个段会有\(0\)也有\(1\)的贡献即可脑力不错的题,当时整个人状态非常玄妙,灵机一动就切了考虑trie树上dp不好,但是子集d......
  • 省选联测 40
    今天题很不错啊!就是我T1写挂了)后浪痛苦面具。#include<algorithm>#include<iostream>#include<cstdio>#include<vector>#include<cstring>usingnamespace......
  • 【LeeCode】424. 替换后的最长重复字符
    【题目描述】给你一个字符串 ​​s​​​ 和一个整数 ​​k​​​ 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 ​​k​​ ......
  • 省选联测39
    直接粘题解tmdA.伯爵我们发现一对排列不一定对应一种方案,一种方案也不一定对应一对排列。考虑如何不算重。首先确定的是归并方式:每个排列对应一些划分,相当于把每个划分......