7.30 mx 模拟赛题解
__S08577__ · · 个人记录
A
题意
给定一张
对于每条边,你都要指定一个该边所属的点,且必须为其两个端点之一。
另外还需要满足,每个点最多拥有一个属于它的边。
求方案数,对
思路
这道题看上去毫无头绪,但是能发现一些规律:
设
当
当
当
我们所求的答案为
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#include<map>
#include<queue>
using namespace std;
#define int long long
#define ll long long
#define Endl cout<<endl;
#define xy cout<<"xy";
#define yx cout<<"yx";
#define pii pair<int,int>
#define ls(rt) tr[rt].ch[0]
#define rs(rt) tr[rt].ch[1]
const int N=5e5+10;//注意修改
const int mod=1e9+7;
const ll MAX=2e14+5;
const int M=2e7+10;
vector <int> ve[N];
int vis[N],node,edge;
void dfs(int x){
if(x){
node++;
vis[x]=1;
for(int i=0;i<ve[x].size();i++){
edge++;
if(!vis[ve[x][i]]) dfs(ve[x][i]);
}
}
}
signed main(){
int n,m,u,v,res=1,x;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
ve[u].push_back(v),ve[v].push_back(u);
}
for(int i=1;i<=n;i++){
edge=0,node=0;
if(!vis[i]){
dfs(i);
edge/=2;
if(edge<node) x=node;
if(edge==node) x=2;
if(edge>node) x=0;
res*=x,res%=mod;
}
}
cout<<res%mod<<endl;
return 0;
}
B
题意
给定正整数
思路
脑抽数论题。
形象化题意:
不难发现,
于是可以将式子转化成
不难发现,这个式子具有对称性,即很多计算重复了两次,我们可以简化一下式子:
-1 是因为
而这个式子
式子又可以转化为:
最后要求的式子便为:
其中,欧拉函数可以利用前缀和优化思想
而质数可以用欧拉筛线性求出。
(不会欧拉筛的请看这里,欧拉函数的请看这里这里)
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#include<map>
#include<queue>
using namespace std;
#define int long long
#define ll long long
#define Endl cout<<endl;
#define xy cout<<"xy";
#define yx cout<<"yx";
#define pii pair<int,int>
#define ls(rt) tr[rt].ch[0]
#define rs(rt) tr[rt].ch[1]
const int N=1e7+10;//注意修改
const int mod=1e9+7;
const int M=2e5+10;
int prime[N],st[N],n,cnt=0,phi[N],s[N],ans;
void Pr(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(st[i]==0){
cnt++;
prime[cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
st[prime[j]*i]=1;
if(i%prime[j]==0) {
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
signed main(){
cin>>n;
Pr();
for(int i=1;i<=n;i++) s[i]=s[i-1]+phi[i];
for(int i=1;i<=cnt;i++) ans+=2*s[n/prime[i]]-1;
cout<<ans;
return 0;
}
/*
*/
C
题意
P8849
思路
若这道题只有操作3,4 ,相信大家都会用树状数组完成。
而这道题要求逆序对的奇偶性,似乎没有什么数据结构能够维护。
但是我们仔细观察发现:交换任意两个数
最难处理的操作是操作1,即区间交换。
设
将
交换后的序列为:
继续将
交换后的序列为:
最后将
总操作次数为:
即:
因为交换任意两个数
而操作二可以转化为序列
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#include<map>
#include<queue>
using namespace std;
#define int long long
#define ll long long
#define Endl cout<<endl;
#define xy cout<<"xy";
#define yx cout<<"yx";
#define pii pair<int,int>
#define ls(rt) tr[rt].ch[0]
#define rs(rt) tr[rt].ch[1]
#define lowbit(x) x&(-x)
const int N=1e7+10;//注意修改
const int mod=1e9+7;
const int Max=2e6+10;
int c[N],a[N];
void add(int x,int k){
for(int i=x;i<=Max;i+=lowbit(i)){
c[i]+=k;
}
}
int search(int x){
int s=0;
for(int i=x;i;i-=lowbit(i)) s+=c[i];
return s;
}
signed main(){
int n,q;
cin>>n>>q;
int f=0;
for(int i=1;i<=n;i++) {
cin>>a[i];
f^=search(Max-2)-search(a[i]);
add(a[i],1);
}
while(q--){
int op,k,l1,r1,l2,r2,n1,n2,N;
cin>>op;
if(op==1){
cin>>l1>>r1>>l2>>r2;
n1=r1-l1+1;
n2=r2-l2+1;
N=l2-r1-1;
f^=N*(n1+n2)+n1*n2;
}
if(op==2){
cin>>l1>>r1>>k;
n1=r1-l1+1;
n2=k-r1;
f^=n1*n2;
}
if(op==3){
int x;
cin>>x;
f^=search(Max-2)-search(x);
add(x,1);
}
if(op==4){
int x;
cin>>x;
f^=search(x);
add(x,1);
}
if(f&1) cout<<"odd"<<endl;
else cout<<"even"<<endl;
}
return 0;
}
/*
*/