2021 杭电多校/中超 第八场记录

1003-Ink on paper

队友写的prim,本题数据卡克鲁斯卡尔

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll x[5005],y[5005];
int cnt,father[5005],vis[50005],cnt2=1;
ll g[5005][5005];
ll dis[5005];
void prim()
{
    for(int i=1;i<=n;i++){
        dis[i]=9*1e18;
        vis[i]=0;
    }
    dis[1]=0;
    for(int j=1;j<=n;j++)
    {
        ll min_len=9*1e18;
        int k;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]<min_len)
            {
                min_len=dis[i];
                k=i;
            }
        }
        vis[k]=1;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]>g[k][i])
                dis[i]=g[k][i];
        }
    }

}

int main(){
    int t;
    cin>>t;
    while(t--){
    cin>>n;
    cnt=0;
    cnt2=1;
    for(int i=1;i<=n;i++)
    father[i]=i;
    for(int i=1;i<=n;i++){
        scanf("%lld %lld",&x[i],&y[i]);
    }
    for(int i=1;i<=n;i++){    //关键代码 
        for(int j=i+1;j<=n;j++){
            g[i][j]=g[j][i]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
        }
    }
    ll ans=0;
    prim();
    for(int i=1;i<=n;i++)
    ans=max(ans,dis[i]);
    printf("%lld\n",ans);
}
    return 0;
        
}
View Code

 

1006-GCD Game

素因子个数当成石子数就好,然后预处理利用一下线性筛拆分的思想。

int x,res[10000007],n;
bool isPrime[10000007];
int Prime[10000007], cnt = 0;
void GetPrime(int n){
    memset(isPrime, 1, sizeof(isPrime));
    isPrime[0] = 0;isPrime[1] = 0;
    for(int i = 2; i <= n; i++){
        if(isPrime[i]){
            Prime[++cnt] = i;
            res[i]=1;
        } 
        for(int j = 1; j <= cnt && i*Prime[j] <= n; j++) {
            isPrime[i*Prime[j]] = 0;
            res[i*Prime[j]]=res[i]+res[Prime[j]];
            if(i % Prime[j] == 0)    break; 
        }
    }
}
void solve(){
    scanf("%d",&n);
    int ans=0;
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        ans=ans^res[x];
    }
    if(ans==0)        printf("Bob\n");
    else            printf("Alice\n");
}

1009-Singing Superstar

多个模式串匹配,ac自动机板子题,现场学的ac自动机。

标记上一个满足条件的位置,判断是否重复。

标记相同模式串编号

const int N = 1e5+5,M=6e5+5;
char s[N],str[N][100];
int fail[M],cnt[N],last[N],vis[N],tail[M],n;
int ch[N][30],idx,tot;

void insert(char *str,int id){
    int cur=0;
    for(int i=0;str[i];++i){
        int idx=str[i]-'a';
        if(!ch[cur][idx])    ch[cur][idx]=++tot;
        cur=ch[cur][idx];
    }
    if(tail[cur]==0){//标记字符串结尾 
        tail[cur]=id;//结尾标记返回编号 
    }
    else{
        vis[id]=tail[cur];//重复标记返回先前位置 
    }
}
void build(){
    queue<int> q;
    for(int j=0;j<26;++j)
        if(ch[0][j]) q.push(ch[0][j]);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for (int j=0;j<26;j++){
            if(ch[now][j]){
                fail[ch[now][j]]=ch[fail[now]][j];
                q.push(ch[now][j]);
            }
            else{
                ch[now][j]=ch[fail[now]][j];
            }
        }
    }
}
void solve(){
    tot=0;
    memset(ch,0,sizeof(ch));
    memset(fail,0,sizeof(fail));
    memset(cnt,0,sizeof(cnt));
    memset(vis,0,sizeof(vis));
    memset(tail,0,sizeof(tail));
    memset(last,-1,sizeof(last));

    scanf("%s",s);
    scanf("%d",&n); 
    for(int i=1;i<=n;++i){
        scanf("%s",str[i]);        
        insert(str[i],i);
    }
    build();
    int cur=0;
    for(int i=0;s[i];++i){
        int idx=s[i]-'a';
        cur=ch[cur][idx];
        int tmp=cur;
        while(tmp){//当前节点
            if(tail[tmp]){
                int flag=i-last[tail[tmp]]-strlen(str[tail[tmp]]);
                if(flag>=0){
                    cnt[tail[tmp]]++, last[tail[tmp]] = i;
                }
            }
            tmp=fail[tmp];
        }
    }
    for(int i=1;i<=n;++i){
        if(vis[i])    printf("%d\n",cnt[vis[i]]);//重复情况 
        else        printf("%d\n",cnt[i]);//不重 
    }
}

 

1004-Counting Stars

操作1,区间求和  操作2 区间减lowbit(ai) 操作3 区间加2^k(2^k <= ai <= 2^(k+1))

区间减去lowbit(ai),就是减去最低位1,对于某一个数ai最多操作log(ai)次,可以暴力维护 时间复杂度 nlognlogn

当区间都置为0,不去操作,考虑一个零标记

区间加2^k  就是最高位前移一位 ,考虑单独维护最高位*2

 

 

#include<bits/stdc++.h>
#define inf 1e18
#define int long long 
#define ull unsigned long long 
#define PI acos(-1.0)
using namespace std;
const int N = 1e5+5;
const int mod=998244353;
int n,x,q;
int a1[N],a2[N],s1[N<<2],s2[N<<2],tag[N<<2],lazy[N<<2];
int lowbit(int x){
    return x&(-x);
}
void pushup(int o){
    s1[o]=(s1[o<<1]+s1[o<<1|1])%mod;//最高位
    s2[o]=(s2[o<<1]+s2[o<<1|1])%mod;//其他位
    tag[o]=tag[o<<1]&tag[o<<1|1];//零标记位 
}
void pushdown(int o){
    lazy[o<<1]=lazy[o<<1]*lazy[o]%mod;
    lazy[o<<1|1]=lazy[o<<1|1]*lazy[o]%mod;
    s1[o<<1]=s1[o<<1]*lazy[o]%mod;
    s1[o<<1|1]=s1[o<<1|1]*lazy[o]%mod;
    tag[o<<1]=tag[o<<1]|tag[o];
    tag[o<<1|1]=tag[o<<1|1]|tag[o];
    if(tag[o<<1])    s2[o<<1]=0;
    if(tag[o<<1|1])    s2[o<<1|1]=0;
    lazy[o]=1;
}
void build(int o,int l,int r){
    lazy[o]=1;//首位乘法的lazy标记 
    tag[o]=0;//零标记 
    if(l==r){
        s1[o]=a1[l],s2[o]=a2[l];
        return ;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    pushup(o);
} 
int query(int o,int l,int r,int ll,int rr){
    if(ll<=l&&rr>=r){
        return (s1[o]+s2[o])%mod;
    }
    pushdown(o);
    int mid=l+r>>1;
    int ans=0;
    if(ll<=mid)    ans=(ans+query(o<<1,l,mid,ll,rr))%mod;
    if(rr>mid)    ans=(ans+query(o<<1|1,mid+1,r,ll,rr))%mod;
    return ans%mod;
}
void upd1(int o,int l,int r,int ll,int rr){
    if(l==r){//对单点暴力操作最多logn 
        if(s2[o]){//当前点还有位可以减去 
            s2[o]=s2[o]-lowbit(s2[o]); 
        }
        else{
            s1[o]=0;//减掉最高位 
            tag[o]=1;//说明当前点为0 
        }
        return ;
    }
    pushdown(o);
    int mid=l+r>>1;
    if(ll<=mid&&!tag[o<<1])    upd1(o<<1,l,mid,ll,rr);
    if(rr>mid&&!tag[o<<1|1]) upd1(o<<1|1,mid+1,r,ll,rr);
    pushup(o);
}
void upd2(int o,int l,int r,int ll,int rr){
    if(ll<=l&&rr>=r){
        s1[o]=s1[o]*2%mod;
        lazy[o]=lazy[o]*2%mod;
        return ;
    }
    pushdown(o);
    int mid=l+r>>1;
    if(ll<=mid)    upd2(o<<1,l,mid,ll,rr);
    if(rr>mid)    upd2(o<<1|1,mid+1,r,ll,rr);
    pushup(o);
}
void solve(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld",&x);
        for(int j=31;j>=0;--j){
            int idx=(1ll<<j);
            if(idx<=x){//找最高位 
                a1[i]=idx;
                a2[i]=x-idx;
                break;
            }
        }
    }
    build(1,1,n);
    scanf("%lld",&q);
    while(q--){
        int op,l,r;
        scanf("%lld%lld%lld",&op,&l,&r);
        if(op==1){//求和 
            int ans=query(1,1,n,l,r);
            printf("%lld\n",ans);
        }
        else if(op==2){//减去lowbit 
            upd1(1,1,n,l,r);
        }
        else{//最高位加 
            upd2(1,1,n,l,r);
        }
    }
}

signed main(){
    int t=1;
    scanf("%lld",&t);
    while(t--){
        solve();
    }
    return 0;
}

 

posted @ 2021-08-13 17:46  PdrEam  阅读(65)  评论(0编辑  收藏  举报