- “度义而后动,是而不见可悔故也。”如果没有把握,就再检查一下;如果有把握,就自信的提交吧,有什么好担忧的呢?
A. The Play Never Ends
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int k;
cin>>k;
k%3==1? cout<<"YES\n":cout<<"NO\n";
}
return 0;
}
B. Perfecto
- 如果排列总和就是完全平方数,输出-1;否则,随机化构造方案即可
- 也可以直接构造方案。具体而言,我们考虑原排列的第一个非法位置,注意到一个完全平方数+1一定不是完全平方数,因此只要把这一位与后一位交换就可以使得当前位合法,同时容易证明下一位也是合法的。
#include <bits/stdc++.h>
using namespace std;
int p[500005];
long long n;
bool pd()
{
long long sum=0;
for(int i=1;i<=n;i++)
{
sum=sum+p[i];
long long x=sqrt(sum);
if(x*x==sum)
{
return false;
}
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
mt19937 myrand(0);
while(T--)
{
cin>>n;
long long sum=n*(n+1)/2;
long long x=sqrt(sum);
if(x*x==sum)
{
cout<<-1<<"\n";
continue;
}
iota(p+1,p+n+1,1);
while(!pd())
{
random_shuffle(p+1,p+n+1);
}
for(int i=1;i<=n;i++)
{
cout<<p[i]<<" ";
}
cout<<"\n";
}
return 0;
}
C. Trapmigiano Reggiano
- 以st为根遍历整棵树,考察从st到en的路径,问题转化为构造一个从树根出发最后回到树根的方案。由于题目只要求一组可行解,所以我们把节点按深度从大到小排序就好了
- 这次你自己想出来,下次就会更加熟练了~
- 再大胆一点,直接以en为根,把所有节点按深度从大到小排序
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005],g[100005];
bool f[100005];
int c[100005],d[100005],fa[100005];
int q[100005];
void dfs1(int n1)
{
for(int v:a[n1])
{
if(v!=fa[n1])
{
d[v]=d[n1]+1;
fa[v]=n1;
dfs1(v);
}
}
}
void col(int n1,int dep)
{
g[dep].push_back(n1);
for(int v:a[n1])
{
if(v!=fa[n1])
{
col(v,dep);
}
}
}
void dfs2(int n1)
{
for(int v:a[n1])
{
if(v!=fa[n1])
{
if(!f[v])
{
col(v,d[n1]);
}
else
{
dfs2(v);
}
}
}
}
bool cmp(int a,int b)
{
return d[a]>d[b];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,st,en;
cin>>n>>st>>en;
for(int i=1;i<=n;i++)
{
a[i].clear();
f[i]=false;
g[i].clear();
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
d[st]=1;
fa[st]=0;
dfs1(st);
int p=en;
while(p!=st)
{
q[d[p]]=p;
f[p]=true;
p=fa[p];
}
q[1]=st;
f[st]=true;
dfs2(st);
for(int i=1;i<=d[en];i++)
{
sort(g[i].begin(),g[i].end(),cmp);
for(int x:g[i])
{
cout<<x<<" ";
}
cout<<q[i]<<" ";
}
cout<<endl;
}
return 0;
}
D1. Infinite Sequence (Easy Version)
#include <bits/stdc++.h>
using namespace std;
int a[200005],s[200005],n;
int calc(long long x)
{
if(x<=n)
{
return a[x];
}
long long y=x/2;
if(y<=n)
{
return s[y];
}
if(y%2==1)
{
return s[n];
}
else
{
return s[n]^calc(y);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
cin>>n;
long long l,r;
cin>>l>>r;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
if(n%2==0)
{
n++;
a[n]=0;
for(int i=1;i<=n/2;i++)
{
a[n]^=a[i];
}
}
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]^a[i];
}
cout<<calc(l)<<"\n";
}
return 0;
}
E. LeaFall
- 别再遇到一道计数期望题就想着套“组合意义”了。回顾之前遇到的“组合意义”的题目,都是因为要统计的对象过于抽象、难以处理,比如“出现次数的立方值”等,所以通过“组合意义”的思维方法把它等价转化成形象、容易处理的形式。可是这道题要统计的对象本身就已经足够形象了呀,你还纠结什么呢?所以,遇到后期题目,应该静下心来从题目本身生发思考,而不是一开始就想着套解法。“套解法”的本质是“速胜论”,而“速胜论”本质上不过是“速败论”的一种表现形式。其实,平时做难题你还是能静下心来思考的,但在赛场上,面对有限的时间,你难免“急于求成”,担心功亏一篑而不敢全力以赴。因而,当此之时,就更要相信你自己,“这道题可能会消耗我一些时间,但我一定可以把它做出来的;即使它真的会把你难倒,现在的你也肯定要为它投入时间,愿‘赌’服‘输’。”心如止水,静气凝神
- 静下心来分距离为1、距离为2(兄弟节点和祖孙节点)、距离>=3三种情况讨论,很轻松就解决这道题啦~
- 计算小技巧:预处理\(c_i=\frac{p_i}{q_i}\)
- 调试小技巧:注释掉一些行,看样例输出的答案有无变化,以此定位出错位置(也就是考虑有哪些情况没有在样例中出现),因为样例中没有发挥显式作用的行出错的概率要远大于已经正常工作了的行
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
long long c[100005],inv[100005];
long long f[100005],mul[100005],sum[100005],ans;
const int mod=998244353;
int power(int n,int p)
{
if(p==0)
{
return 1;
}
long long tmp=power(n,p/2);
if(p%2==1)
{
return tmp*tmp%mod*n%mod;
}
return tmp*tmp%mod;
}
void dfs(int u,int fa)
{
sum[u]=f[u];
long long tmp1=0,tmp2=0,tmp3=0;
for(int v:a[u])
{
if(v!=fa)
{
ans=ans+mul[u]*mul[v]%mod*inv[u]%mod*inv[v]%mod*(1-c[u])%mod*(1-c[v])%mod;
ans=ans-f[u]*f[v]%mod;
if(fa)
{
ans=ans+(f[fa]-(1-c[fa])*(1-c[u])%mod*mul[fa]%mod*inv[u]%mod)*(f[v]-(1-c[v])*(1-c[u])%mod*mul[v]%mod*inv[u]%mod)%mod*inv[u]%mod;//中间点消失
ans=ans-f[fa]*f[v]%mod;
ans=ans+mul[fa]*mul[v]%mod*inv[u]%mod*inv[u]%mod*(1-c[fa])%mod*(1-c[v])%mod*(1-c[u])%mod;//中间点存在
}
dfs(v,u);
ans=ans+tmp1*(f[v]-(1-c[v])*(1-c[u])%mod*mul[v]%mod*inv[u]%mod)%mod*inv[u]%mod;
ans=ans+tmp2*mul[v]%mod*inv[u]%mod*(1-c[v])%mod*(1-c[u])%mod;
ans=ans-tmp3*f[v]%mod;
tmp1=(tmp1+(f[v]-(1-c[v])*(1-c[u])%mod*mul[v]%mod*inv[u]%mod))%mod;
tmp2=(tmp2+mul[v]%mod*inv[u]%mod*(1-c[v])%mod)%mod;
tmp3=(tmp3+f[v])%mod;
ans=ans+sum[u]*sum[v]%mod;
sum[u]=(sum[u]+sum[v])%mod;
ans%=mod;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
a[i].clear();
}
for(int i=1;i<=n;i++)
{
long long p,q;
cin>>p>>q;
c[i]=p*power(q,998244351)%mod;
inv[i]=q*power(p,998244351)%mod;
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
f[i]=(1-c[i])%mod;
mul[i]=1;
for(int v:a[i])
{
mul[i]=mul[i]*c[v]%mod;
}
long long sum=0;
for(int v:a[i])
{
long long tmp=mul[i];
mul[i]=mul[i]*inv[v]%mod;
mul[i]=mul[i]*(1-c[v])%mod;
sum=(sum+mul[i])%mod;
mul[i]=tmp;
}
f[i]=f[i]*sum%mod;
}
ans=0;
dfs(1,0);
cout<<(ans+mod)%mod<<endl;
}
return 0;
}
- 感觉%mod太多影响思绪,就去了解了一下modint,改写之后程序清楚多了!
- 单个1直接参与运算竟然没有问题,或许是因为聪明的编译器会把它自动转换成modint类型吧!
- 另外,如果要批量更改某个区间内的关键字,可以先把这段代码复制到一个新的文件里,修改后再复制回去
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
const int mod=998244353;
struct mint
{
unsigned int x;
mint(int o=0)
{
x=o;
}
mint operator =(int o)
{
return x=o,*this;
}
mint operator +=(mint o)
{
return x=(x+o.x)%mod,*this;
}
mint operator -=(mint o)
{
return x=(x-o.x+mod)%mod,*this;
}
mint operator *=(mint o)
{
return x=1ll*x*o.x%mod,*this;
}
friend mint operator +(mint a,mint b)
{
return a+=b;
}
friend mint operator -(mint a,mint b)
{
return a-=b;
}
friend mint operator *(mint a,mint b)
{
return a*=b;
}
};
mint c[100005],inv[100005];
mint f[100005],mul[100005],sum[100005],ans;
int power(int n,int p)
{
if(p==0)
{
return 1;
}
long long tmp=power(n,p/2);
if(p%2==1)
{
return tmp*tmp%mod*n%mod;
}
return tmp*tmp%mod;
}
void dfs(int u,int fa)
{
sum[u]=f[u];
mint tmp1=0,tmp2=0,tmp3=0;
for(int v:a[u])
{
if(v!=fa)
{
ans+=mul[u]*mul[v]*inv[u]*inv[v]*(1-c[u])*(1-c[v]);
ans-=f[u]*f[v];
if(fa)
{
ans+=(f[fa]-(1-c[fa])*(1-c[u])*mul[fa]*inv[u])*(f[v]-(1-c[v])*(1-c[u])*mul[v]*inv[u])*inv[u];//中间点消失
ans-=f[fa]*f[v];
ans+=mul[fa]*mul[v]*inv[u]*inv[u]*(1-c[fa])*(1-c[v])*(1-c[u]);//中间点存在
}
dfs(v,u);
ans+=tmp1*(f[v]-(1-c[v])*(1-c[u])*mul[v]*inv[u])*inv[u];
ans+=tmp2*mul[v]*inv[u]*(1-c[v])*(1-c[u]);
ans-=tmp3*f[v];
tmp1+=(f[v]-(1-c[v])*(1-c[u])*mul[v]*inv[u]);
tmp2+=mul[v]*inv[u]*(1-c[v]);
tmp3+=f[v];
ans+=sum[u]*sum[v];
sum[u]+=sum[v];
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
a[i].clear();
}
for(int i=1;i<=n;i++)
{
long long p,q;
cin>>p>>q;
c[i]=p*power(q,998244351)%mod;
inv[i]=q*power(p,998244351)%mod;
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
f[i]=1-c[i];
mul[i]=1;
for(int v:a[i])
{
mul[i]*=c[v];
}
mint sum=0;
for(int v:a[i])
{
sum+=mul[i]*inv[v]*(1-c[v]);
}
f[i]*=sum;
}
ans=0;
dfs(1,0);
cout<<ans.x<<endl;
}
return 0;
}