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

咕咕咕的冲动如此强烈x

T1x:

看完题目想了想,感觉把gcd不为1的强行放在一组,看作一个连通块,最后考虑连通块之间的组合方式就可以了。

然后维护这个连通块可以写并查集可以连边跑dfs怎么着都行…

然而我在处理数字分解质因数这里T掉了,原因是一个很显然的优化写法我基本没怎么写过。线性筛的时候记录每个数是被哪个质数标记过的,分解一个数的时候直接处理记录下来的质数就可以。

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,t;
long long mod=1e9+7,ans,sum;
int num[2000010],pri[2000010],cnt,vis[2000010],pre[2000010];
int fa[200010];
void work(){
    for(int i=2;i<=1000000;i++){
        if(!vis[i]){
            pri[++cnt]=i;
            pre[i]=i;
        }
        for(int j=1;j<=cnt&&i*pri[j]<=1000000;j++){
            vis[i*pri[j]]=1;
            pre[i*pri[j]]=pri[j];
            if(i%pri[j]==0)break;
        }
    }
}
long long ks(long long x,long long k){
    long long num=1;
    while(k){
        if(k&1)num=num*x%mod;
        x=x*x%mod;
        k>>=1;
    }
    return num;
}
int get(int x){
    if(fa[x]==x)return x;
    else return fa[x]=get(fa[x]);
}
int main()
{
    scanf("%d",&t);
    work();
    while(t--){
        scanf("%d",&n);
        sum=n;
        for(int i=1;i<=cnt;i++)num[pri[i]]=0;
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);

            while(x>1){
                int y=pre[x];
                while(x%y==0)x/=y;
                if(!num[y])num[y]=i;
                else{
                    int x1=get(num[y]),x2=get(i);
                    if(x1!=x2){
                        fa[x2]=x1;
                        sum--;
                    }
                    num[y]=i;
                }
            }

        }
        ans=((ks(2ll,sum)%mod-2)%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

T2y:

如果直接做的话,显然是从1开始,枚举路径状态,看看这个状态能达到的节点有哪些,并根据这些节点所连的边能达到的点的集合拓展下一位的状态。最后看长度为d的状态有多少个所能到达的点的集合不为空,统计答案。

但是这样要枚举的状态太多了。

于是考虑把路径拆成两部分,对每个点都求一次能达到的路径的答案,存下每个长度为d的一半的路径状态能达到哪些点。可以倒序从n开始求,最后一次求的就正好是1能达到的一半路径的状态。枚举前后两半的路径状态,若两者存在交集,即两半路径存在可以相连的中间点,那么答案+1。

#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;
int n,m,d,x1,x2,ans;
bitset<110>sum0[110],sum1[110],f[1<<11],g[1<<11];
//void add(int x,int y,int z){
//    ver[++tot]=y;
//    Next[tot]=head[x];
//    head[x]=tot;
//    edge[tot]=z;
//}
int main()
{
    scanf("%d%d%d",&n,&m,&d);
    x1=d/2,x2=d-x1;
    for(int i=1,x,y,z;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        if(z){
            sum1[x][y]=1;
            sum1[y][x]=1;
        }
        else{
            sum0[x][y]=1;
            sum0[y][x]=1;
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=0;j<(1<<11);j++)f[j].reset();
        f[1][i]=1;
        for(int j=1;j<(1<<x2);j++){
            for(int k=1;k<=n;k++){
                if(f[j][k]){
                    f[j<<1]|=sum0[k];
                    f[j<<1|1]|=sum1[k];
                }
            }
        }
        for(int j=0;j<(1<<x2);j++){
            g[j][i]=f[(1<<x2)|j].any();
        }
    }
    for(int i=0;i<(1<<x2);i++){
        for(int j=0;j<(1<<x1);j++){
            if((g[i]&f[(1<<x1)|j]).any())ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

T3z:

强行模拟这个过程是可以骗到分的,虽然我没骗到多少…

然而正解好像是个更难写的模拟…

首先观察n个任务,发现如果有任务与上一个相同,或者处在上一个任务到下一个任务的路径上,那么这个任务可以忽略不计。简化以后的任务序列就成为了一左一右的过程,每一次线段平移都与上一次走相反方向。

然后可以用链表串起这些有效任务,在询问线段长度小于最小的两个任务间距的时候,答案是一个一次函数。如果有两个任务之间的距离小于询问线段的长度,就合并相连的三个位移,答案还是一个一次函数。

然而并不会写,虽然刚刚重新下载题解的时候好像看到发标程了…

垃圾选手什么都菜,被赶了出来【大雾】

原文地址:https://www.cnblogs.com/chloris/p/11614771.html

时间: 2024-08-30 13:51:03

2019.9.28 csp-s模拟测试54 反思总结的相关文章

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<cst

[考试反思]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后一

2019.10.30 csp-s模拟测试94 反思总结

头一次做图巨的模拟题OWO 自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233 T1: 对于XY取对数=Y*log(x) 对于Y!取对数=log(1*2*3*...*Y)=log1+log2+log3+...+logY 因为数字大小不超过1e5,直接累加最后比较就可以了 #include<iostream> #include<cstdio> #include<cmath> using namespace std; int t,x,y; double a,b

2019.9.19 csp-s模拟测试47 反思总结

思路接近正解?都想到了?这都是借口呀. 没有用的,往前走吧. T1:Emotional Flutter 我的做法和题解不太一样,我把s放在最后考虑了. 因为出发以后步幅是一样的,所以每一个黑条可以ban掉一段出发点.把黑条的左右边界%k存成区间,每个黑条可以存一个或者两个区间[跨越k这个边界].然后像以前写区间覆盖的贪心一样按左端点排序,看看有没有长至少为s的空余. 代码: #include<iostream> #include<cstdio> #include<cstrin

2019.9.20 csp-s模拟测试48 反思总结

头疼,不说废话了,祝大家rp++. T1: 暴力枚举,n3. 枚举两个串开始匹配的位置,每一次尽量修改. #include<iostream> #include<cstdio> using namespace std; int n,k,cnt,num,ans; char a[310],b[310]; int main() { scanf("%d%d",&n,&k); scanf("%s",a+1); scanf("%

2019.9.26 csp-s模拟测试52 反思总结

刚刚写了一个小时的博客没了,浏览器自动刷新. 一!个!小!时! 鼠标键盘电脑哪个都不能摔,气死我了. 垃圾选手T1T2没思路,T3倒是想出来得比较早,靠T3撑着分数. 数据结构学傻选手,属实垃圾. T1平均数: 一个序列的所有数如果减去x,那么平均数也会减去x.可以二分这个x,统计序列里平均数小于0的序列的个数,含义为原序列平均数小于x的序列的个数.最后统计值小于k且最接近k的x就是所求答案. 序列的平均数小于0,那么序列的和也一定小于0.表现在前缀和上即为一个区间的sumr<suml-1,转化

2019.9.27 csp-s模拟测试53 反思总结

这个起名方式居然还有后续?! 为什么起名不是连续的?! T1想了半天,搞出来了,结果数组开小[其实是没注意范围].T2概率期望直接跳,后来翻回来写发现自己整个理解错了期望的含义[何].T3错误想到赛道修建结果来了个错误贪心. 关于T2破罐子破摔输出k居然骗了二十分这件事…… T1u: 一开始各种想偏,维护哪种值是奇数或偶数个,考虑每次操作影响哪些值变化…这些全都跑出来了. 大概过了一个世纪那么长,突然想着能不能直接优化操作的过程啊,然后对暴力进行钻研,终于开始想到差分. 然后觉着nq的复杂度过不

2019.9.29 csp-s模拟测试55 反思总结

不咕咕咕是一种美德[大雾] 头一次体会到爆肝写题解??? 这次考试我们没赶上,是后来掐着时间每个人自己考的.我最后的分数能拿到152…熟悉的一题AC两题爆炸. 强烈吐槽出题人起名走心 T1联: 发现每一次加入一个区间的操作,只有区间的l或者r+1有可能成为答案.那么考虑能不能用这两个点代表一整个区间,维护全局最靠左的0在什么地方. 把每个操作的l和r+1都存下来,离散化,建一棵线段树.每一次区间操作都针对线段树上的a[l]-a[r+1]-1这部分(a[x]为x离散化以后的排序,即线段树里的位置)