2024.11.2 2024ICPC成都站

EssentialSingularity發表於2024-11-03

Solved:7/13

Penalty:793

Rank:40

Rank(ucup):152


L. Recover Statistics

輸出 50 個 P50、45 個 P95,4 個 P99 和 1 個 P99+1 即可。

#include<bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int a,b,c;
    cin>>a>>b>>c;
    cout<<100<<'\n';
    for(int i=1;i<=50;++i)cout<<a<<' ';
    for(int i=1;i<=45;++i)cout<<b<<' ';
    for(int i=1;i<=4;++i)cout<<c<<' ';
    cout<<c+1<<'\n';
}

A. Arrow a Row

題意:用形如 >—>>> (中間可以有任意多個 -)來構造給定字串,如果可以輸出方案。\(n\leq 2\times 10^5\)

簡單構造,但是卡了很久。

結論是 a[1],a[n-2],a[n-1],a[n]必須是>,且至少要有一個-。

構造就是先把最後一段連續的>都造出來,再造前面的>。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;

void solve(){
    string a;
    cin>>a;
    int n=a.size();
    if(a[0]=='-'||a[n-1]=='-'||a[n-2]=='-'||a[n-3]=='-'){
        cout<<"No\n";
        return;
    }
    int pos=-1;
    for(int i=n-4;i>=0;--i)if(a[i]=='-'){pos=i;break;}
    if(!~pos){
        cout<<"No\n";
        return;
    }
    vector<pii> ans;
    for(int i=n-1;i>=pos+3;--i)ans.emplace_back(0,i);
    for(int i=1;i<pos;++i)if(a[i]=='>')ans.emplace_back(i,pos+3);
    cout<<"Yes "<<ans.size()<<'\n';
    for(int i=0;i<ans.size();++i)cout<<ans[i].first+1<<' '<<ans[i].second-ans[i].first+1<<'\n';
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}

G.Expanding Array

題意:給一個序列,每次可以在兩個數中間插入它們的按位與、按位或、按位異或。問最多能構造出多少個不同的數。\(n\leq 2\times 10^5\)

能構造出的數只有 \(0,a_i,a_i\land a_{i+1},a_i\lor a_{i+1},a_i\oplus a_{i+1},a_i\backslash a_{i+1},a_{i+1}\backslash a_i\)。全都扔進 set 然後輸出 size 即可。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int n;
    cin>>n;
    vector<int> a(n);
    for(int& x:a)cin>>x;
    set<int> s;
    s.insert(0);
    for(int i=0;i<a.size()-1;++i){
        s.insert(a[i]);
        s.insert(a[i+1]);
        s.insert(a[i]&a[i+1]);
        s.insert(a[i]|a[i+1]);
        s.insert(a[i]^a[i+1]);
        s.insert(a[i]&(a[i]^a[i+1]));
        s.insert(a[i+1]&(a[i]^a[i+1]));
    }
    cout<<s.size()<<'\n';
}

I.Good Partitions

題意:維護一個序列,支援單點修改,查詢存在多少個 \(k\) 滿足將序列分成每 \(k\) 個一段每段都是單調不減的。\(n\leq 2\times 10^5\)

設所有滿足 \(a_i>a_{i+1}\)\(i\) 的集合為 \(S\),則答案就是 \(\gcd(S)\)

因此只需支援插入、刪除一個數,維護全體的 \(\gcd\)

一開始寫了個逆天的 vector 套 set,要列舉約數複雜度達到了 \(O((n+q)d(n)\log n)\),然後 TLE on 13。

然後改成了線段樹維護 gcd,不存在的位置就填 0,複雜度 \(O(n\log^2 n)\)

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;

const int N=2e5+5;
int d[N];
void init(int n){
    for(int i=1;i<=n;++i)
        for(int j=i;j<=n;j+=i)++d[j];
}

#define lc (x<<1)
#define rc (x<<1|1)
#define mid ((l+r)>>1)
int n,q,x,y,a[N],s[N*4];
void bld(int x,int l,int r){
    if(l==r){s[x]=a[l]>a[l+1]?l:0;return;}
    bld(lc,l,mid),bld(rc,mid+1,r);
    s[x]=__gcd(s[lc],s[rc]);
}
void upd(int x,int l,int r,int p,int v){
    if(l==r){s[x]=v;return;}
    if(p<=mid)upd(lc,l,mid,p,v);
    else upd(rc,mid+1,r,p,v);
    s[x]=__gcd(s[lc],s[rc]);
}

void solve(){
    cin>>n>>q,d[0]=n;
    for(int i=1;i<=n;++i)cin>>a[i];
    if(n==1){
        cout<<1<<'\n';
        while(q--)cin>>x>>y,cout<<1<<'\n';
        return;
    }
    bld(1,1,n-1);
    cout<<d[s[1]]<<'\n';
    while(q--){
        cin>>x>>y;
        if(x>1&&a[x-1]>a[x]&&a[x-1]<=y)upd(1,1,n-1,x-1,0);
        if(x>1&&a[x-1]<=a[x]&&a[x-1]>y)upd(1,1,n-1,x-1,x-1);
        if(x<n&&a[x]>a[x+1]&&y<=a[x+1])upd(1,1,n-1,x,0);
        if(x<n&&a[x]<=a[x+1]&&y>a[x+1])upd(1,1,n-1,x,x);
        a[x]=y;
        cout<<d[s[1]]<<'\n';
    }
}

int main(){
    init(2e5);
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}

J. Grand Prix of Ballance

簡單模擬,map 亂殺。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;

const int N=1e5+5;
int n,m,q,op,id,x;
pii a[N];
int r[N];
set<pii> e;

void solve(){
    cin>>n>>m>>q;
    for(int i=1;i<=m;++i)a[i]={0,i};
    memset(r,0,sizeof(int)*(n+1));
    e.clear();
    int cur=0;
    while(q--){
        cin>>op;
        if(op==1){
            cin>>x;
            cur=x;
        }
        else if(op==2){
            cin>>id>>x;
            if(x!=cur||e.find(pii(id,x))!=e.end())continue;
            a[id].first-=m-r[x];
            e.insert({id,x}),++r[x];
        }
        else{
            cin>>id>>x;
            if(x!=cur||e.find(pii(id,x))!=e.end())continue;
            e.insert({id,x});
        }
    }
    sort(a+1,a+m+1);
    for(int i=1;i<=m;++i)cout<<a[i].second<<' '<<-a[i].first<<'\n';
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;
    cin>>T;
    while(T--)solve();
}

B. Athlete Welcome Ceremony

題意:一個全是abc的字串,其中某些位置未定,要求相鄰位置不同,多次詢問,每次詢問限制 a 的數量不超過 x,b 的數量不超過 y,c 的數量不超過 z,求方案數。 \(1\leq n\leq 300,1\leq q\leq 10^5\)

先 dp 求出 恰好使用 i 個 a、j 個 b、k 個 c 的方案數,然後三維字首和。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;

const int N=305,mod=1e9+7;
int n,q,c[3];
string a;
ll f[N][N][N][3],s[N][N][N];

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    cin>>n>>q>>a,a=" "+a;
    for(int i=1;i<=n;++i)if(a[i]!='?')++c[a[i]-'a'];
    f[1][0][0][0]=f[0][1][0][1]=f[0][0][1][2]=1;
    for(int i=0;i<=n;++i)
        for(int j=0;i+j<=n;++j)
            for(int k=0;i+j+k<=n;++k)if(i+j+k>0){
                if(a[i+j+k]=='a')f[i][j][k][1]=f[i][j][k][2]=0;
                if(a[i+j+k]=='b')f[i][j][k][0]=f[i][j][k][2]=0;
                if(a[i+j+k]=='c')f[i][j][k][0]=f[i][j][k][1]=0;
                if(i+j+k<n){
                    (f[i+1][j][k][0]+=f[i][j][k][1]+f[i][j][k][2])%=mod;
                    (f[i][j+1][k][1]+=f[i][j][k][0]+f[i][j][k][2])%=mod;
                    (f[i][j][k+1][2]+=f[i][j][k][0]+f[i][j][k][1])%=mod;
                }
            }
    for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j)
            for(int k=0;k<=n;++k){
                if(i+j+k==n)s[i][j][k]=f[i][j][k][0]+f[i][j][k][1]+f[i][j][k][2];
                if(i>0)s[i][j][k]+=s[i-1][j][k];
                if(j>0)s[i][j][k]+=s[i][j-1][k];
                if(k>0)s[i][j][k]+=s[i][j][k-1];
                if(i>0&&j>0)s[i][j][k]-=s[i-1][j-1][k];
                if(i>0&&k>0)s[i][j][k]-=s[i-1][j][k-1];
                if(j>0&&k>0)s[i][j][k]-=s[i][j-1][k-1];
                if(i>0&&j>0&&k>0)s[i][j][k]+=s[i-1][j-1][k-1];
                s[i][j][k]=(s[i][j][k]%mod+mod)%mod;
            }
    while(q--){
        int x,y,z;
        cin>>x>>y>>z;
        x=min(x+c[0],n),y=min(y+c[1],n),z=min(z+c[2],n);
        cout<<s[x][y][z]<<'\n';
    }
}

K. Magical Set

題意:給一個集合,每次可選一個數除掉它的一個非 1 約數,且需保證集合中任何時刻沒有相同的數。求最多能操作的次數。

最優方案下每次一定除的一定是質數。因此求出每個數及其所有約數的質因子數量 \(p_i\),然後對每個數向它的約數連一條 \(p_i-p_j\) 的邊,二分圖最大權匹配即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;

const int V=6e5+5,E=3e7+5,inf=0x3f3f3f3f;
int s,t,v=0,e=1,fir[V],to[E],nxt[E],w[E],c[E];
inline void adde(int x,int y,int z,int t){
	to[++e]=y,nxt[e]=fir[x],fir[x]=e,w[e]=z,c[e]=t;
	to[++e]=x,nxt[e]=fir[y],fir[y]=e,w[e]=0,c[e]=-t;
}
int dis[V],q[E];
bool vis[V];
bool spfa(){
	memset(dis,63,sizeof(dis));
	memset(vis,0,sizeof(vis));
	int l=1,r=0;
	q[++r]=t,dis[t]=0;
	while(l<=r){
		int u=q[l++];vis[u]=0;
		for(int i=fir[u],v=to[i];i;v=to[i=nxt[i]]){
			if(!w[i^1]||dis[v]<=dis[u]+c[i^1])continue;
			dis[v]=dis[u]+c[i^1];
			if(!vis[v])vis[v]=1,q[++r]=v;
		}
	}
	return dis[s]<inf;
}
int cur[V];
int dfs(int u,int flow){
	if(u==t||!flow)return flow;
	vis[u]=1;
	int nowf=flow;
	for(int& i=cur[u];i;i=nxt[i]){
		int v=to[i];
		if(dis[v]+c[i]!=dis[u]||vis[v])continue;
		int f=dfs(v,min(w[i],nowf));
		w[i]-=f,w[i^1]+=f;
		if(!(nowf-=f))return flow;
	}
	return flow-nowf;
}
int MCMF(){
	int flow=0,res=0;
	while(spfa()){
		memcpy(cur,fir,sizeof(cur));
		memset(vis,0,sizeof(vis));
		int f=dfs(s,inf);
		flow+=f,res+=dis[s]*f;
	}return res;
}

const int N=305;
map<int,int> id;
int n,a[N],p[V];
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    cin>>n;
    s=++v,t=++v;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        if(!id.count(a[i]))id[a[i]]=++v;
        adde(s,id[a[i]],1,0);
        for(int j=1;j*j<=a[i];++j)if(!(a[i]%j)){
            if(!id.count(j))id[j]=++v;
            if(!id.count(a[i]/j))id[a[i]/j]=++v;
        }
    }
    for(auto &[x,u]:id){
        int tt=x;
        for(int i=2;i*i<=tt;++i)if(!(tt%i)){
            while(!(tt%i))tt/=i,++p[u];
        }
        if(tt>1)++p[u];
        adde(u,t,1,0);
    }
    for(int i=1;i<=n;++i)
        for(auto &[x,u]:id)
            if(!(a[i]%x))adde(id[a[i]],u,1,-(p[id[a[i]]]-p[u]));
    cout<<-MCMF()<<'\n';
}

相關文章