9.28 csp-s模拟测试54 x+y+z

T1 x

求出每个数的质因数,并查集维护因子相同的数,最后看一共有多少个联通块,$ans=2^{cnt}-2$

但是直接分解会$T$,埃筛是个很好的选择,或者利用每个数最多只会有1个大于$\sqrt{n}$的质因子,线筛$1e6$内的素数,每次只需枚举$1e3$的质因数就行,复杂度也可以过去

#include<iostream>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<cstring>
#include<vector>
#define ll long long
#define mod 1000000007
using namespace std;
ll T,n,ans,a[100100],prime[100100],fa[100100],num,pr[1001000],tot;
bitset<100100>vis;
bitset<1001000>v;
vector<int>ve[1001000];
ll read()
{
    ll aa=0,bb=1;char cc=getchar();
    while(cc>‘9‘||cc<‘0‘){if(cc==‘-‘) bb=-1;cc=getchar();}
    while(cc>=‘0‘&&cc<=‘9‘){aa=(aa<<3)+(aa<<1)+(cc^‘0‘);cc=getchar();}
    return aa*bb;
}
ll quick(ll x,ll p)
{
    ll as=1;
    while(p){
        if(p&1) as=as*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return as;
}
ll find(ll x)
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
    return fa[x];
}
void init()
{
    for(int i=2;i<=1000000;i++){
        if(v[i]) continue;prime[++tot]=i;
        for(int j=i;j<=1000000;j+=i){
            v[j]=1;
            ve[j].push_back(i);
        }
    }
}
int main()
{
    T=read();init();
    while(T--){
        n=read();ans=0;num=0;vis.reset();memset(pr,0,sizeof(pr));
        for(int i=1;i<=n;i++) a[i]=read(),fa[i]=i;
        for(int i=1;i<=n;i++){
            for(int j=0;j<ve[a[i]].size();j++){
                if(pr[ve[a[i]][j]]) fa[find(i)]=find(pr[ve[a[i]][j]]);
                else pr[ve[a[i]][j]]=i;
            }
        }
        for(int i=1;i<=n;i++){
            int f=find(i);
            if(!vis[f]) vis[f]=1,num++;
        }
        ans=(quick(2,num)-2+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

x

T2 y

$bitset$的灵活应用

一开始的思路是$2^{20}$枚举状态,记忆化搜索,$f[i][sta]$表示从i点出发能否走出$sta$的状态(状态的第一位表示长度),但是空间开不下,时间也扛不住

所以改变策略,只记录一半的状态,最后枚举中间点

$f[i][sta][j]$表示起点为$i$,终点为$j$,中间为状态$sta$是否可行

正常需要枚举一个点,一个状态,然后在枚举一个点,再枚举与第二个点有边相连的点,如果前两个点之间的$sta$状态可行,那么第一个点与第三个点之间$sta<<1|h[i].w$也是可行的

但是,时间显然不优秀

$bitset$就有用了,如果两个点之间的$sta$状态是可行的,那么第一个点与这个状态的终点和第二个点的连边是一样的,所以建边的时候用$bitset$邻接表,再加一维表示是$0$还是$1$,$bitset$合并就行,最后只需要枚举状态和中点,看是否能拼成这个状态

还有就是要在每个状态的第一位表示长度,不然$01$和$001$状态是分不清的。对于$01$串为奇数的要处理好$len/2$与$len/2+1$两个长度的关系

#include<iostream>
#include<cstdio>
#include<cstring>
#include<bitset>
using namespace std;
int n,m,d,ans;
bitset<99>f[99][(1<<12)+5],bt[2][99];
int read()
{
    int aa=0,bb=1;char cc=getchar();
    while(cc>‘9‘||cc<‘0‘){if(cc==‘-‘) bb=-1;cc=getchar();}
    while(cc>=‘0‘&&cc<=‘9‘){aa=(aa<<3)+(aa<<1)+(cc^‘0‘);cc=getchar();}
    return aa*bb;
}
int main()
{
    n=read();m=read();d=read();int dd=d/2,dis=d-dd;
    int u,v,c;
    for(int i=1;i<=m;i++){
        u=read();v=read();c=read();
        bt[c][u][v]=1;bt[c][v][u]=1;
        f[u][c|2][v]=1;f[v][c|2][u]=1;
    }
    for(int i=1;i<=n;i++){
        for(int sta=2;sta<(1<<(dis+1));sta++){
            for(int j=1;j<=n;j++){
                if(!f[i][sta][j]) continue;
                f[i][sta<<1|1]|=bt[1][j];
                f[i][sta<<1|0]|=bt[0][j];
            }
        }
    }
    for(int i=0;i<(1<<d);i++){
        bool flag=0;
        for(int j=1;j<=n;j++){
            if(f[1][i>>dd|(1<<dis)][j]&&f[j][i&((1<<dd)-1)|(1<<dd)].count()){
                flag=1;
                break;
            }
        }
        if(!flag&&dd!=dis){
            for(int j=1;j<=n;j++){
                if(f[1][i>>dis|(1<<dd)][j]&&f[j][i&((1<<dis)-1)|(1<<dis)].count()){
                    flag=1;
                    break;
                }
            }
        }
        ans+=flag;
    }
    printf("%d\n",ans);
    return 0;
}

y

T3 z

咕了

不想退役就应该踏实

原文地址:https://www.cnblogs.com/jrf123/p/11611362.html

时间: 2024-10-01 09:22:32

9.28 csp-s模拟测试54 x+y+z的相关文章

2019.9.28 csp-s模拟测试54 反思总结

咕咕咕的冲动如此强烈x T1x: 看完题目想了想,感觉把gcd不为1的强行放在一组,看作一个连通块,最后考虑连通块之间的组合方式就可以了. 然后维护这个连通块可以写并查集可以连边跑dfs怎么着都行… 然而我在处理数字分解质因数这里T掉了,原因是一个很显然的优化写法我基本没怎么写过.线性筛的时候记录每个数是被哪个质数标记过的,分解一个数的时候直接处理记录下来的质数就可以. #include<iostream> #include<cstdio> #include<cmath>

[考试反思]0928csp-s模拟测试54:转瞬

咕了好久,也没什么想说的. 下一场就又爆炸了... T3特判打丢一句话丢了14分,剩下其实都还好. T1: 给我的第一感觉是建图找联通块,但既然只要找联通块为什么不直接并查集呢? 对于每一个数字合并它的所有因子,求出现过的因子形成几个联通块,特殊处理1. 二营长比我快了整整5分钟做出来的. 1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 #define mod 1000000007 5 #define i

模拟测试54

T1: 所有不互质的数对一定在同一集合内. 并查集维护每个数所在集合,以数对为链合并. 但是这样复杂度为$O(n^2)$的. 考虑优化,两个数不互质,意味着他们之间有相同质因子,把每个数分解质因数,和他的质因子合并即可. 线筛处理出最小质因子后可以$O(logn)$求所有质因子. 时间复杂度$O(nlogn)$. T2: 考虑状压,设数组$dp[i][j]$,表示经过$i$条路径,经过路径状态为$j$的情况存不存在. 时间复杂度$O(nm2^d)$,需要优化. 折半搜索,先DP前一半,再DP后一

csp-s模拟测试54x,y,z题解

题面:https://www.cnblogs.com/Juve/articles/11606834.html x: 并差集,把不能分到两个集合里的元素和并到一起,设连通块个数为cnt,则答案为:$2^cnt-2$ #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<vector> #def

微信在线信息模拟测试工具(基于Senparc.Weixin.MP)

目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具在线DEMO:http://weixin.senparc.com/SimulateTool Senparc.Weixin.MP是一个开源的微信SDK项目,地址:https://github.com/JeffreySu/WeiXinMPSDK (其中https://github.com/Jeffrey

noip模拟测试11

T1:string 第一眼秒出思路,这不就是排序那道题的加强版吗? 然而歪?解复杂度虽然是对的,但常数过大,竟被卡到70 歪?解:(实际上std写的就是这个,但据说std被卡掉了 OAO) 因为字符集很小,所以我们可以把区间排序改为区间查询和覆盖 即:先查询区间内所有字符的个数,再从左端点开始按照大小关系依次将长度为字符个数的区间修改为该字符. 期望复杂度O ( 26*mlogn ),实际复杂度O ( 26*mlogn*(巨大的常数) ) 所以需要一(feng)定(kuang)的卡常 正?解:

[考试反思]0929csp-s模拟测试55:沦陷

菜得过分. 面对T1的大板子不知所措,然后T2的贪心不小心把排序语句删了... T1这种大模板啊...其实我是觉得我能打出来的,然后先用一个小时码了一个2k. 然后做T2想贪心就出来了.十分钟码完T3暴力之后回T1打对拍瞬间爆炸. 于是又重新打了一个2k,WA0.对拍发现. 然后考试就没几分钟了交暴力走了. 不要打完就跑,记得早点对拍改进思路. T1: 的确是挺裸的线段树.离散化或者权值线段树都可以. 但是考场上两个都打出来都死了. 最后用离散化A的. 1 #include<cstdio> 2

[考试反思]1003csp-s模拟测试58:沉淀

稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使用的话,切记计算内存,一点都不能开大. T1: 直接根号筛,拿map也能过. 遍历map直接begin和end啊... 1 #include<cstdio> 2 int Cnt[202]; 3 struct hash_map{ 4 int cnt,fir[10000020],l[6666666],

2016年上半年软考真题在线模拟测试,提前知晓你的成绩

2016年上半年软考于5月21日结束了,考试完想知道结果的急切心理,几乎每个经历过上学时代的人都能深刻体验到.如果你想知道你考的怎么样,如果你想要提前知道你的成绩,如果你想知道你哪个地方出错了,如果你想知道你哪个地方知识掌握的不够想要更深入的去理解,那就来希赛软考学院吧!希赛软考学院提供2016年上半年软考真题在线模拟测试,有标准的参考答案,有专业老师的解析视频,让你提前知晓你的成绩,让你再次巩固学习. 希赛授课专家介绍 张友生,计算机应用技术博士,软考培训教程系列丛书主编,考试指定教材<系统分