2019.8.22(膜你赛)
表示今天是自闭的一天,话说这是我假期里第一次写在学校考试(虽然有的题可能网上都有)
今天考试的题目再次属于雅礼集训的题目qwq。
T1:
题目描述(由于我太懒了,所以我直接就贴图了(逃~)):
这道题的思路我在刚开始的时候其实就想到了,但是在写的时候,脑子一抽,没有想到使用并查集进行维护,而且自己在写的时候,稍微在实现时跑偏了,最终只拿到了10分qwq。
这道题其实很简单,就是使用并查集将这不同的数形成连通块,然后查询连通块的个数,最后应用结论:
\[\text { ans }=2^{n}-2
\]
这样我们就可以十分简单的解决掉这道题。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
template <typename type>
void scan(type &x){
type f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
const int mod=1e9+7;
const int N=1e6+7;
#define ll long long
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
//int gcd(int m,int n)
// {
// while (n != 0)
// {
// int t = m % n;
// m = n;
// n = t;
// }
// return m;
//}
//void dfs(){
// for(int i=1;i<=n;i++){
//
// }
//}
int pre[N],val[N],n,m,cnt,t;
void get_prime(){
memset(val,0,sizeof(val));
int cnt=0;
for(int i=2;i<=1e6+1;i++){
if(val[i]==0){
val[i]=i;
pre[++cnt]=i;
}
for(int j=1;j<=cnt;j++){
if(pre[j]>val[i]||pre[j]>(1e6+1)/i)break;
val[i*pre[j]]=pre[j];
}
}
// printf("%d\n",cnt);
// for(int i=1;i<=cnt;i++){
// printf("%d ",pre[i]);
// }
}
int vis[N],a[N];
//int vis1[N];
//int num=0;
int fa[N];
int get(int x){
if(fa[x]==x)return fa[x];
fa[x]=get(fa[x]);
return fa[x];
}
int main(){
freopen("x.in","r",stdin);
freopen("x.out","w",stdout);
get_prime();
scan(t);
while(t--){
scan(n);
cnt=0;
memset(vis,0,sizeof(vis));
// if(n>15){
int maxx=0;
for(int i=1;i<=n;i++){
scan(a[i]);
maxx=max(maxx,a[i]);
// fa[a[i]]=a[i];
}
for(int i=1;i<=maxx;i++)fa[i]=i;
for(int i=1;i<=n;i++){
if(a[i]==1){
cnt++;
continue;
}
ll x=a[i],lim=sqrt(a[i]);
// int flag=0;
if(val[x]==x){
continue;
}
for(int j=1;pre[j]<=lim&&val[x]!=x;j++){
if(x%pre[j]!=0)continue;
// flag=1;
while(x%pre[j]==0) x/=pre[j];
if(get(a[i])!=get(pre[j])){
fa[get(a[i])]=get(pre[j]);
}
}
if(val[x]==x) fa[get(a[i])]=get(x);
}
for(int i=1;i<=n;i++){
if(a[i]==1)continue;
if(vis[get(a[i])]==0){
cnt++;
vis[get(a[i])]=1;
}
}
printf("%lld\n",ksm(2,cnt)-2);
// for(int i=1;i<=n;i++){
// printf("%d ",fa[a[i]]);
// }
// puts("");
// sort(a+1,a+1+n);
// for(int i=1;i<=n;i++){
//// scan(a[i]);
// vis1[a[i]]=1;
// if(a[i]==1)continue;
// int flag=0,num=0,flag1=0;
// for(int j=1;pre[j]<=sqrt(a[i]);j++){
// if(a[i]%pre[j]!=0)continue;
// flag1=1;
// if(vis1[pre[j]])num++;
// if((a[i]/pre[j])%pre[j]==0&&vis1[pre[j]])break;
// if(flag==1){
// vis[pre[j]]=1;
// }
// if(flag==0){
// if(vis[pre[j]]==1){
// flag=1;
// }else{
// vis[pre[j]]=1;
// }
// }
// a[i]/=pre[j];
// }
// if(flag1==0)vis[a[i]]=1;
//// if(vis1[a[i]]&&flag1)num++;
// if(flag)
// i--,
// n--;
// i-=num;
// n-=num;
// }
// printf("%lld\n",(ksm(2,n)-2)%mod);
// printf("%d\n",n);
// }else{
// for(int i=1;i<=n;i++){
// scan(a[i]);
// }
//
// }
}
return 0;
}
无脑T1 qwq
T2
T2打的暴力,直接挂掉>﹏<
先放题目吧:
这道题我,,,,,,不会!
题解告诉我,这是meet in the middle(不会,再见)。
要留代码吗?
算了,留一个std吧(手动狗头)
#include<bits/stdc++.h>
using namespace std;
const int maxn=90+10,maxmask=1<<20/2+1;
int n,m,d,d1,d2,ans;
bitset<maxn> g0[maxn],g1[maxn],dp[maxmask],f[maxmask];
int main(){
freopen("y.in","r",stdin);
freopen("y.out","w",stdout);
scanf("%d%d%d",&n,&m,&d);
for(int i=1,u,v,c;i<=m;++i){
scanf("%d%d%d",&u,&v,&c);
if(c)
g1[u][v]=g1[v][u]=true;
else
g0[u][v]=g0[v][u]=true;
}
d2=d/2;d1=d-d2;
for(int u=n;u;--u){
for(int i=0;i<maxmask;++i)
dp[i].reset();
dp[1][u]=true;
for(int x=1;x<1<<d1;++x)
for(int v=1;v<=n;++v)
if(dp[x][v]){
dp[x<<1]|=g0[v];
dp[x<<1|1]|=g1[v];
}
for(int x=0;x<1<<d1;++x)
f[x][u]=dp[1<<d1|x].any();
}
for(int i=0;i<1<<d1;++i)
for(int j=0;j<1<<d2;++j)//����dp����״̬������1Ϊ��ͷ��չ������
if((dp[1<<d2|j]&f[i]).any())
++ans;
printf("%d\n",ans);
return 0;
}