Gym 104270 The 2018 ICPC Asia Qingdao Regional Programming Contest (The 1st Universal Cup, Stage 9: Qingdao)
A. Sequence and Sequence
B. Kawa Exam
可以发现,对答案会产生影响的只有割边,把所有边双缩起来,然后就是一个森林。
考虑一个树的时候怎么做,就是对于每条边求出这条边两端的众数个数,考虑线段树合并,每次动态维护子树内的众数和子树外的众数。
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,k;
int x[N],y[N],id[N];
int a[N];
struct Edge
{
int to,next;
}edge[N<<1];
int head[N],cnt;
void add_edge(int u,int v)
{
cnt++;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
return;
}
struct Segment_Tree_RMQ
{
int index(int l,int r)
{
return (l+r)|(l!=r);
}
#define ls index(l,mid)
#define rs index(mid+1,r)
struct Node
{
int mx;
}tree[N*2];
void push_up(int i,int l,int r)
{
int mid=(l+r)/2;
tree[i].mx=max(tree[ls].mx,tree[rs].mx);
return;
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i].mx=0;
return;
}
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i,l,r);
return;
}
void modify(int i,int l,int r,int u,int v)
{
if(l==r)
{
tree[i].mx+=v;
return;
}
int mid=(l+r)/2;
if(u<=mid) modify(ls,l,mid,u,v);
else modify(rs,mid+1,r,u,v);
push_up(i,l,r);
return;
}
int query(int l,int r)
{
return tree[index(l,r)].mx;
}
#undef ls
#undef rs
}rmq;
struct Segment_Tree
{
struct Node
{
int ls,rs;
int mx1,mx2;
}tree[N*25];
int tot,rt[N];
void clear()
{
tot=0;
for(int i=1;i<=n;i++)
rt[i]=0;
return;
}
int new_node()
{
int now=++tot;
tree[now].ls=tree[now].rs=0;
tree[now].mx1=tree[now].mx2=0;
return now;
}
void push_up(int i,int l,int r)
{
int mid=(l+r)/2;
tree[i].mx1=max(tree[tree[i].ls].mx1,tree[tree[i].rs].mx1);
tree[i].mx2=max(tree[i].ls?tree[tree[i].ls].mx2:rmq.query(l,mid),tree[i].rs?tree[tree[i].rs].mx2:rmq.query(mid+1,r));
return;
}
void add(int &i,int l,int r,int u,int v)
{
if(!i)
{
i=new_node();
if(l==r) tree[i].mx1=0,tree[i].mx2=rmq.query(l,r);
}
if(l==r)
{
tree[i].mx1+=v,tree[i].mx2-=v;
return;
}
int mid=(l+r)/2;
if(u<=mid) add(tree[i].ls,l,mid,u,v);
else add(tree[i].rs,mid+1,r,u,v);
push_up(i,l,r);
return;
}
int merge(int u,int v,int l,int r)
{
if(!u) return v;
if(!v) return u;
if(l==r)
{
tree[u].mx1+=tree[v].mx1;
tree[u].mx2-=rmq.query(l,r)-tree[v].mx2;
return u;
}
int mid=(l+r)/2;
tree[u].ls=merge(tree[u].ls,tree[v].ls,l,mid);
tree[u].rs=merge(tree[u].rs,tree[v].rs,mid+1,r);
push_up(u,l,r);
return u;
}
int query_t1(int i,int l,int r,int L,int R)
{
if(!i) return 0;
if(L<=l&&r<=R) return tree[i].mx1;
int mid=(l+r)/2;
if(R<=mid) return query_t1(tree[i].ls,l,mid,L,R);
else if(L>mid) return query_t1(tree[i].rs,mid+1,r,L,R);
else return max(query_t1(tree[i].ls,l,mid,L,R),query_t1(tree[i].rs,mid+1,r,L,R));
}
int query_t2(int i,int l,int r,int L,int R)
{
if(!i) return rmq.query(l,r);
if(L<=l&&r<=R) return tree[i].mx2;
int mid=(l+r)/2;
if(R<=mid) return query_t2(tree[i].ls,l,mid,L,R);
else if(L>mid) return query_t2(tree[i].rs,mid+1,r,L,R);
else return max(query_t2(tree[i].ls,l,mid,L,R),query_t2(tree[i].rs,mid+1,r,L,R));
}
}T;
int dfn[N],low[N],Index;
bool bridge[N+N];
void tarjan(int u,int prev)
{
dfn[u]=low[u]=++Index;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) bridge[i]=bridge[i^1]=true;
}
else if(i!=(prev^1)) low[u]=min(low[u],dfn[v]);
}
return;
}
int bel[N],tot;
vector<int>block[N];
void dfs(int u)
{
bel[u]=tot;
block[tot].emplace_back(u);
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(bel[v]||bridge[i]) continue;
dfs(v);
}
return;
}
vector<int>G[N];
void rebuild()
{
fill(dfn+1,dfn+n+1,0);
fill(low+1,low+n+1,0);
for(int i=1;i<=cnt;i++)
bridge[i]=false;
Index=0;
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i,0);
fill(bel+1,bel+n+1,0);
tot=0;
for(int i=1;i<=n;i++)
block[i].clear();
for(int i=1;i<=n;i++)
if(!bel[i])
{
tot++;
dfs(i);
}
for(int i=1;i<=tot;i++)
G[i].clear();
for(int u=1;u<=n;u++)
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(bel[u]==bel[v]) continue;
G[bel[u]].emplace_back(bel[v]);
}
return;
}
int siz[N],dep[N];
vector<int>color;
void init(int u,int father)
{
siz[u]=block[u].size();
dep[u]=dep[father]+1;
for(int v:G[u])
{
if(v==father) continue;
init(v,u);
siz[u]+=siz[v];
}
for(int t:block[u])
color.emplace_back(a[t]);
return;
}
int res[N];
int top[N];
void dfs(int u,int father,int topf)
{
top[u]=topf;
for(int v:G[u])
{
if(v==father) continue;
dfs(v,u,topf);
T.rt[u]=T.merge(T.rt[u],T.rt[v],1,k);
}
for(int t:block[u])
T.add(T.rt[u],1,k,a[t],1);
res[u]=T.query_t1(T.rt[u],1,k,1,k)+T.query_t2(T.rt[u],1,k,1,k);
return;
}
int ans[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
fill(head+1,head+n+1,0);
cnt=1;
for(int i=1;i<=m;i++)
{
cin>>x[i]>>y[i];
add_edge(x[i],y[i]);
add_edge(y[i],x[i]);
id[i]=cnt;
}
k=*max_element(a+1,a+n+1);
rebuild();
rmq.build(1,1,k);
long long sum=0;
T.clear();
fill(siz+1,siz+n+1,0);
for(int i=1;i<=tot;i++)
if(!siz[i])
{
color.clear();
init(i,0);
for(int c:color)
rmq.modify(1,1,k,c,1);
dfs(i,0,i);
sum+=res[i];
for(int c:color)
rmq.modify(1,1,k,c,-1);
}
for(int i=1;i<=m;i++)
if(!bridge[id[i]]) ans[i]=sum;
else
{
if(dep[bel[x[i]]]<dep[bel[y[i]]]) swap(x[i],y[i]);
ans[i]=res[bel[x[i]]]+sum-res[top[bel[x[i]]]];
}
for(int i=1;i<m;i++)
cout<<ans[i]<<" ";
cout<<ans[m]<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
C. Flippy Sequence
如果
如果
如果
如果
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1000005;
int n;
char s[N],t[N];
int a[N];
void solve()
{
cin>>n;
cin>>s;
cin>>t;
for(int i=0;i<n;i++)
if(s[i]==t[i]) a[i]=1;
else a[i]=0;
int cnt=0;
for(int i=0,j=0;i<n;i=j)
{
while(j<n&&a[i]==a[j]) j++;
if(a[i]) continue;
cnt++;
}
long long ans=0;
if(cnt==0) ans=(long long)n*(n-1)/2+n;
else if(cnt==1) ans=2*(n-1);
else if(cnt==2) ans=6;
cout<<ans<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
D. Magic Multiplication
可以发现,我们如果确定了
#include<iostream>
#include<cstdio>
using namespace std;
const int N=200005;
int n,m,len;
int c[N];
int a[N],b[N];
bool check(int v)
{
int cur=1;
a[1]=v;
for(int i=1;i<=m;i++)
{
if(cur<=len&&c[cur]%a[1]==0) b[i]=c[cur]/a[1],cur++;
else if(cur+1<=len&&(c[cur]*10+c[cur+1])%a[1]==0&&(c[cur]*10+c[cur+1])/a[1]<=9) b[i]=(c[cur]*10+c[cur+1])/a[1],cur+=2;
else return false;
}
for(int i=2;i<=n;i++)
{
a[i]=-1;
for(int j=1;j<=m;j++)
if(b[j]!=0)
{
int val=-1;
if(cur<=len&&c[cur]%b[j]==0) val=c[cur]/b[j],cur++;
else if(cur+1<=len&&(c[cur]*10+c[cur+1])%b[j]==0&&(c[cur]*10+c[cur+1])/b[j]<=9) val=(c[cur]*10+c[cur+1])/b[j],cur+=2;
else return false;
if(a[i]!=-1&&a[i]!=val) return false;
else a[i]=val;
}
else
{
if(cur<=len&&c[cur]==0) cur++;
else return false;
}
}
return cur==len+1;
}
void solve()
{
cin>>n>>m;
string str;
cin>>str;
len=str.size();
for(int i=1;i<=len;i++)
c[i]=str[i-1]-'0';
for(int v=1;v<=9;v++)
if(check(v))
{
for(int i=1;i<=n;i++)
cout<<a[i];
cout<<" ";
for(int i=1;i<=m;i++)
cout<<b[i];
cout<<"\n";
return;
}
cout<<"Impossible\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
E. Plants vs. Zombies
二分答案,问题转换成判断每个点
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n;
long long m;
int a[N];
long long b[N];
bool check(long long x)
{
long long tot=0;
for(int i=1;i<=n;i++)
b[i]=0;
for(int i=1;i<=n;i++)
if(b[i]<x)
{
long long t=(x-b[i]+a[i]-1)/a[i];
tot+=t*2-1;
if(tot>m) return false;
b[i+1]+=a[i+1]*(t-1);
}
else tot++;
return true;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
long long l=1,r=*max_element(a+1,a+n+1)*m,ans=0;
while(l<=r)
{
long long mid=(l+r)/2;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
F. Tournament
打个表找找规律,可以发现
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1005;
int n,k;
int a[N][N];
int lowbit(int x)
{
return x&-x;
}
void solve()
{
cin>>n>>k;
if(k>lowbit(n)-1)
{
cout<<"Impossible\n";
return;
}
for(int i=1;i<=n;i++)
a[0][i]=i;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
a[i][j]=a[i-1][j];
int len=lowbit(i);
for(int j=1;j<=n;j+=len*2)
for(int k=0;k<len;k++)
swap(a[i][j+k],a[i][j+len*2-1-k]);
}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<"\n";
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
G. Repair the Artwork
H. Mirror
I. Soldier Game
将问题可以转化成我们有长度为
考虑枚举最小值
合并节点就是
初值设成
将所有区间排序,从小到大,依次删除每个区间就行了,删除的时候可以将线段树上的节点设成
#include<iostream>
#include<cstdio>
#include<vector>
#include<tuple>
#include<algorithm>
using namespace std;
const int N=100005;
const long long INF=4557430888798830399;
int n;
int a[N];
struct Segment_Tree
{
#define ls i*2
#define rs i*2+1
struct Node
{
int l,r;
long long mx[2][2];
}tree[N*4];
Node merge(const Node &a,const Node &b)
{
Node c;
c.l=a.l,c.r=b.r;
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
c.mx[i][j]=INF;
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
for(int k=0;k<=1;k++)
c.mx[i][j]=min(c.mx[i][j],max(a.mx[i][k],b.mx[k][j]));
return c;
}
void push_up(int i)
{
tree[i]=merge(tree[ls],tree[rs]);
return;
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
if(l==r)
{
tree[i].mx[0][0]=a[l];
if(l+1<=n) tree[i].mx[0][1]=a[l]+a[l+1];
else tree[i].mx[0][1]=INF;
if(l-1>=1) tree[i].mx[1][0]=-INF;
else tree[i].mx[1][0]=INF;
tree[i].mx[1][1]=INF;
return;
}
int mid=(l+r)/2;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i);
return;
}
void modify(int i,int u,int v)
{
if(tree[i].l==tree[i].r)
{
if(v==1) tree[i].mx[0][0]=INF;
else tree[i].mx[0][1]=INF;
return;
}
if(u<=tree[ls].r) modify(ls,u,v);
else modify(rs,u,v);
push_up(i);
return;
}
Node query(int i,int l,int r)
{
if(l<=tree[i].l&&tree[i].r<=r) return tree[i];
if(r<=tree[ls].r) return query(ls,l,r);
else if(l>=tree[rs].l) return query(rs,l,r);
else return merge(query(ls,l,r),query(rs,l,r));
}
#undef ls
#undef rs
}T;
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
T.build(1,1,n);
vector<tuple<int,int,int>>seg;
for(int i=1;i<=n;i++)
{
seg.emplace_back(a[i],i,1);
if(i+1<=n) seg.emplace_back(a[i]+a[i+1],i,2);
}
sort(seg.begin(),seg.end());
long long ans=INF;
for(auto [v,i,len]:seg)
{
ans=min(ans,T.query(1,1,n).mx[0][0]-v);
T.modify(1,i,len);
}
cout<<ans<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
J. Books
先把价格为
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m;
int a[N];
int b[N],tot;
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
tot=0;
for(int i=1;i<=n;i++)
if(a[i]==0) m--;
else b[++tot]=a[i];
if(m<0)
{
cout<<"Impossible\n";
return;
}
if(m==tot)
{
cout<<"Richman\n";
return;
}
long long ans=0;
for(int i=1;i<=m;i++)
ans+=b[i];
int v=*min_element(b+m+1,b+tot+1);
ans+=v-1;
cout<<ans<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
K. Airdrop
L. Sub-cycle Graph
不会数数爬了,可以看官方的题解
https://sua.ac/wiki/2018-icpc-qingdao/l/
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
const int MOD=1000000007;
const int INV2=500000004;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=(long long)res*a%MOD;
a=(long long)a*a%MOD,b>>=1;
}
return res;
}
int getinv(int a)
{
return qpow(a,MOD-2);
}
int fac[N+N],ifac[N+N];
void init(int n=200000)
{
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=(long long)fac[i-1]*i%MOD;
ifac[n]=qpow(fac[n],MOD-2);
for(int i=n;i>=1;i--)
ifac[i-1]=(long long)ifac[i]*i%MOD;
return;
}
int C(int n,int m)
{
if(m>n) return 0;
if(m==0||m==n) return 1;
return (long long)fac[n]*ifac[m]%MOD*ifac[n-m]%MOD;
}
int n;
long long m;
void solve()
{
cin>>n>>m;
if(m==0) cout<<1<<"\n";
else if(m>n) cout<<0<<"\n";
else if(m==n)
{
int ans=(long long)fac[n-1]*INV2%MOD;
cout<<ans<<"\n";
}
else
{
int ans=0;
int pre=1;
for(int i=1;i<=n-m;i++)
{
pre=(long long)pre*(2*i-1)%MOD;
ans=(ans+(long long)C(n,n-m-i)*fac[m-i]%MOD*C(m-1,i-1)%MOD*C(m+i,2*i)%MOD*pre)%MOD;
}
cout<<ans<<"\n";
}
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
init();
int T;
cin>>T;
while(T--)
solve();
return 0;
}
M. Function and Function
可以发现最后就是在
#include<iostream>
#include<cstdio>
using namespace std;
int x,k;
int calc(int x)
{
if(x==0) return 1;
if(x==1||x==2||x==3) return 0;
if(x==4) return 1;
if(x==5) return 0;
if(x==6) return 1;
if(x==7) return 0;
if(x==8) return 2;
if(x==9) return 1;
return -1;
}
int f(int x)
{
if(x==0) return 1;
int sum=0;
while(x>0)
sum+=calc(x%10),x/=10;
return sum;
}
void solve()
{
cin>>x>>k;
for(int i=1;i<=k;i++)
{
x=f(x);
if(x==0||x==1)
{
x^=(k-i)&1;
break;
}
}
cout<<x<<"\n";
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
int T;
cin>>T;
while(T--)
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话