题意
题解
代码
#include
using namespace std;
int main() {
int a,b;
cin>>a>>b;
cout<<2*b-a<<'\n';
return 0;
}
题意
题解
位运算是每一位独立的运算,所以一位位看规律就行。因为c尽可能大,所以尽量选1
a | b | c可选 | c终选 |
---|---|---|---|
0 | 0 | 0,1 | 1 |
0 | 1 | 0 | 0 |
1 | 0 | 0 | 0 |
1 | 1 | 0,1 | 1 |
可以取巧,先让c中63位全为1,由表格得ab相同时c选1,不同时c选0,所以直接c-a^b
代码
#include
using namespace std;
int main() {
long long a,b;
cin>>a>>b;
long long c=(1ll<<63)-1ll;//这样写似乎不会溢出
cout<<(c-(a^b))<<'\n';
return 0;
}
题意
题解
代码
#include
using namespace std;
long long f[110];
void solve() {
long long x,ans;
cin>>x;
for(int i=1;i<=100;i++)
if(f[i]==x) {cout<<i<<'\n'; return ;}//恰好相等直接输出
else if(f[i]>x) {ans=i;break;}//否则找到第一个比x大的数
cout<<((f[ans]-x < x-f[ans-1]) ? ans:ans-1)<<'\n';//比较与前一个数列哪个更近,输出
}
int main() {
f[1]=f[2]=1;
for(int i=3;i<105;i++) f[i]=f[i-1]+f[i-2];//预处理出要查找的范围内的数列
int t;
cin>>t;
while(t--) solve();
return 0;
}
题意
题解
代码
#include
using namespace std;
int main() {
int n;
cin>>n;
long long sum=0,x;
for(int i=1;i<=n;i++) {
cin>>x;
sum+=x-i;
}
cout<<(sum&1 ? "ZZZ":"SSZ")<<'\n';
return 0;
}
题意
题解
代码
#include
#include
using namespace std;
void solve() {
int n;
cin>>n;
vector<vector<int>> pos(n);
int h=0;//注意初始化,最高的高度
for(int i=1;i<=n;i++) {
int t; cin>>t;
h=max(h,t);
pos[t].push_back(i);//高度为t的编号加上一个i
}
if(pos[h].size()>1) {cout<<"-1\n"; return ;}//根只一个
for(int i=0;i<h;i++)
if(pos[i].size()<pos[i+1].size()) {//底的点数量不得小于高的点数量
cout<<"-1\n";
return ;
}
cout<<pos[h][0]<<'\n';
for(int i=0;i<h;i++)
for(int j=0;j<pos[i].size();j++)//链式构造
cout<<pos[i][j]<<' '<<pos[i+1][min(j,int(pos[i+1].size()-1))]<<'\n';
}
int main() {
cin.tie(0)->sync_with_stdio(false);
int T;
cin>>T;
while(T--) solve();
return 0;
}
题意
题解
对于一家公司求拓扑序数量时:用树形dp求解
f[u]:以u为根的子树的拓扑数
sz[u]:以u为根的子树大小(节点数量)
例如:
将u的两颗子树v1,v2合并求f[u]:合并后的f[u]=f[v1]*f[v2]*C(v1+v2,v1)
组合数解释:子树所有节点sz[v1]+sz[v2]进行排序,子树v1内部的拓扑数为f[v1],v2的拓扑数为f[v2],当两树节点排列时不相互插入,即前sz[v1]个数全是子树v1的节点,后sz[v2]个数全是子树v2的节点时,这种情况下sz[v1]+sz[v2]进行排序会有f[v1]*f[v2]个拓扑数,但v1,v2两子树中的节点为互不分高低的,所以两子树可以随意的互相插入,只需保持各子树内部保持拓扑序即可,所以两子树插入的方法有C(sz[v1]+sz[v2],sz[v1]),即保持sz[v1]+sz[v2]个位置中sz[v1]个数是拓扑序
拓展到n家公司同理,只需把所有公司都看成一颗连在虚根上的子树即可,拓展后的计算公式为
f [ u ] = ( ∏ v ∈ s o n ( u ) f [ v ] ) ⋅ ( s z [ u ] − 1 ) ! ∏ v ∈ s o m ( u ) s z [ v ] ! f [ u ] = ( s z [ u ] − 1 ) ! ⋅ ∏ v ∈ s o n ( u ) f [ v ] s z [ v ] ! f[u]=(\prod_{v\in son(u)}f[v])\cdot \frac{(sz[u]-1)!}{\prod_{v\in som(u)}sz[v]!}\\ f[u]=(sz[u]-1)!\cdot\prod_{v\in son(u)}\frac{f[v]}{sz[v]!} f[u]=(v∈son(u)∏f[v])⋅∏v∈som(u)sz[v]!(sz[u]−1)!f[u]=(sz[u]−1)!⋅v∈son(u)∏sz[v]!f[v]
代码
#include
using namespace std;
#define int long long
const int N=1e5+10,mod=1e9+7;
int h[N],e[N],ne[N],idx;//建树
int f[N],sz[N];//dp数组,size数组
int fac[N],rev[N];//排列及其逆元数组
int qp(int a,int b) {//快速幂
int res=1;
while(b) {
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int C(int n,int m) {//求组合数
return fac[n]*rev[m]%mod*rev[n-m]%mod;
}
void add(int a,int b) {//加边
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u) {//dfs树形dp
f[u]=1,sz[u]=1;
for(int i=h[u];~i;i=ne[i]) {
int v=e[i];
dfs(v);
sz[u]+=sz[v];
f[u]=f[u]*f[v]%mod*C(sz[u]-1,sz[v])%mod;
}
}
int dp(int n) {//返回每一个公司的拓扑数
idx=0;
for(int i=1;i<=n;i++) h[i]=-1;//初始化
for(int i=2;i<=n;i++) {//输入边
int x;
cin>>x;
add(x,i);
}
dfs(1);//dfs计算
return f[1];//f[1]即为此公司的拓扑数
}
signed main() {
cin.tie(0)->sync_with_stdio(false);
fac[0]=1;//预处理排列数数组
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;
rev[N-1]=qp(fac[N-1],mod-2);
for(int i=N-1;i>0;i--) rev[i-1]=rev[i]*i%mod;
int n,m,sum=0,res=1;
cin>>n;//n个公司,看做n个子树
while(n--) {
cin>>m;
sum+=m;
res=res*dp(m)%mod*C(sum,m)%mod;//按公式计算答案
}
cout<<res<<'\n';
return 0;
}