ZROI 2022 没打的场
_Luminescence_ · · 个人记录
CSP7连 附加赛 Day1
A
一道好题,启示我们要从多个角度思考。并且思考这道题不可做的原因是什么,然后解决它/换思路。
首先我们发现字符串中的关系十分的混乱,有很多位置需要相等,容易想到维护这些相等的位置,可以用并查集,假设最后维护出了
const int N=2010,p=1e9+7;
int fa[N],cnt,n,m,k;
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
void merge(int x,int y){fa[get(x)]=get(y);}
int power(int a,int b){
int c=1;
for(;b;b>>=1){
if(b&1)c=1ll*c*a%p;
a=1ll*a*a%p;
}
return c;
}
int main()
{
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=n-k+1;i++)for(int j=i;j<=(i*2+k)>>1;j++)merge(j,i*2+k-j-1);
for(int i=1;i<=n;i++)if(fa[i]==i)cnt++;
cout<<power(m,cnt);
return 0;
}
B
容易想到假设没有行列之间的影响的话,就用堆维护最大值即可。
发现假设行列选择方案数固定后,对答案的贡献值是一定的。即为
于是我们可以枚举行的方案数,更新最大值即可。
const int N=1010;
int a[N][N],s[N],t[N],n,m,k,p,ans=-1e18,res=0;
priority_queue<int>q1,q2;
signed main()
{
n=read(),m=read(),k=read(),p=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
s[i]+=a[i][j];
t[j]+=a[i][j];
}
}
for(int i=1;i<=n;i++)q1.push(s[i]);
for(int i=1;i<=m;i++)q2.push(t[i]);
for(int i=1;i<=k;i++){
s[i]=s[i-1]+q1.top();
q1.push(q1.top()-p*m);
q1.pop();
}
for(int i=0;i<=k;i++){
ans=max(ans,res+s[k-i]-i*(k-i)*p);
res+=q2.top();q2.push(q2.top()-p*n);q2.pop();
}
cout<<ans;
return 0;
}
但受 一开始假设行列不影响的贪心思想 的影响,很容易写出一下的错误贪心:
const int N=1010;
int a[N][N],s[N],t[N],n,m,k,p,cnt_s,cnt_t,ans;
priority_queue<int>q1,q2;
int main()
{
n=read(),m=read(),k=read(),p=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
s[i]+=a[i][j];
t[j]+=a[i][j];
}
}
for(int i=1;i<=n;i++)q1.push(s[i]);
for(int i=1;i<=m;i++)q2.push(t[i]);
while(k--){
int A=q1.top(),B=q2.top();
if(A-cnt_t*p>B-cnt_s*p){
cnt_s++;
ans+=A-cnt_t*p;
q1.pop();
q1.push(A-m*p);
}
else {
cnt_t++;
ans+=B-cnt_s*p;
q2.pop();
q2.push(B-n*p);
}
}
cout<<ans;
return 0;
}
这样为什么是错的呢?
很容易构造出AB相等的情况,发现无法在规定的数据范围内决策选A还是B。
CSP7连 附加赛 Day2
A
观察题面中求 LCA 的代码容易发现,答案正确的充要条件是
考虑如何统计,设
对于
然后这就是个范德蒙德卷积,有
const int N=2e5+10,p=998244353;
vector<int>e[N];
int n,m,d[N],f[N][20],fac[N],inv[N];
int power(int a,int b){
int c=1;
for(;b;b>>=1){
if(b&1)c=c*a%p;
a=a*a%p;
}
return c;
}
void dfs(int x){
for(int i=1;i<=17;i++)f[x][i]=f[f[x][i-1]][i-1];
for(int y:e[x]){
if(y!=f[x][0]){
f[y][0]=x,d[y]=d[x]+1;
dfs(y);
}
}
}
int LCA(int x,int y){
if(d[x]<d[y])swap(x,y);
for(int i=17;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
void init(){
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%p;
inv[n]=power(fac[n],p-2);
for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%p;
}
int C(int x,int y){
return fac[x]*inv[y]%p*inv[x-y]%p;
}
signed main()
{
n=read();
init();
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].pb(y),e[y].pb(x);
}
d[1]=1;
dfs(1);
m=read();
while(m--){
int x=read(),y=read(),z;
z=LCA(x,y);
if(d[x]>d[y])swap(x,y);
printf("%lld\n",C(d[x]+d[y]-2*d[z],d[x]-d[z])*power(power(2,d[x]+d[y]-2*d[z]),p-2)%p);
}
return 0;
}
CSP7连 附加赛 Day5
C
树形dp,设
记得初始化。
const int N=1e5+10,p=998244353;
vector<int>e[N];
int n,ans,f[N],g[N],w[N],cnt[N];
void dfs(int x,int fa){
cnt[x]=1;
g[x]=w[x];
f[x]=w[x]*w[x]%p;
for(int y:e[x]){
if(y!=fa){
dfs(y,x);
f[x]=(f[x]+f[x]*cnt[y]+2*g[x]*g[y]+cnt[x]*f[y])%p;
g[x]=(g[x]+g[x]*cnt[y]+g[y]*cnt[x])%p;
cnt[x]=(cnt[x]+cnt[x]*cnt[y])%p;
}
}
ans=(ans+f[x])%p;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0);
cout<<ans;
return 0;
}