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