2024.11.2 2024ICPC成都站

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';
}
posted @ 2024-11-03 15:39  EssnSlaryt  阅读(197)  评论(0编辑  收藏  举报