1. 程式人生 > 其它 >2021 杭電多校/中超 第八場記錄

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;
}