[考试反思]1219省选模拟3: 释怀

有些东西渐渐就远去了。。。不必挂念。

只有时间才拥有如此力量。我们能做的,唯有释怀。

这次的题格外顺手,大概是我的强项了。

但是考得还是不够好吧。。。感觉可以更高的

今天迎来了学了OI一年多比较重要的一个成就:(虽说是在考后)

AC1000道题!还是挺不容易的。

第1000道题是今天的T3。大部分是自己思考的,题也不是很简单,挺好的。

挺过了联赛,现在想要等到下一次整百,可能就要到3月份了。

我还能在OI多久呢?

回到这场考试。

T1的数据范围只有10000,让我想起了ALO那道题50000数据被我随机化AC。

然而这题可以构造毒瘤数据所以正确率没有那么高,但是除了随机化啥也不会写。

于是拿一个60走人(其实很满意了)。

T2一眼秒,AC自动机+拓扑dp,当然需要tarjan。

tarjan?啊。。。好像不会写了,弃了。

然后正解真的就是这个,自闭。。。

T3其实是最先开始做的题,因为测试1里做的那道题有提到积性函数,然后就想了一下这题的这玩意显然也就是积性函数。

然后P=2的就很好说了。很快写完。然后又研究了一下P=2017,也就证明了结论但是复杂度不对,一共80分滚粗。

这点分拿到之后就啥都没干了。T2写了个AC自动机但是没有tarjan没有用。然后就不知道该干什么了。

tarjan这种东西吧。。。

至少现在,应该是真的会了。。。幸亏联赛没考不然就退役了。

T1:好题

题意:树上每个点有色,求最小联通块含有k种颜色。n<=10000,k<=5,颜色<=n

k<=5一定是突破口。但是颜色那么多怎么办?

随机化。把所有的颜色分成k类,同类的视为一种颜色。

然后树上状压dp就可以得到含有k类颜色的最小联通块。

显然找到的方案一定是合法的,但不一定是最优的。

考虑最优方案的联通块所包含的k种颜色,你能找出这个解当且仅当这k种颜色被恰好分为了不同的k类。

合法的总方案是$k!$个(内部顺序任意,所以是排列)。而对这k中颜色分类的总方案数就是$k^k$。

所以单次随机化得到正解的概率是$\frac{k!}{k^k}$。在k=5时大约是0.04

这样的话,只要进行50次随机化,正确率就已经高达87%了。然而你让它一直clock跑下去肯定是不会错的。

单次随机化的复杂度是$O(3^kn)$。然而我懒得写枚举子集了,于是单次复杂度变为$O(4^kn)$。

还是可以过的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 10003
 4 int n,k,fir[S],l[S<<1],to[S<<1],co[S],ec,cnt,c,ans=S,tans,sz[S],dp[S][33],re[S],Co[S];
 5 void dfs(int p,int fa){
 6     dp[p][1<<co[p]]=1;
 7     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
 8         dfs(to[i],p);
 9         for(int a=1;a<1<<k;++a)for(int b=1;b<1<<k;++b)dp[p][a|b]=min(dp[p][a|b],dp[p][a]+dp[to[i]][b]);
10     }ans=min(ans,dp[p][(1<<k)-1]);
11 }
12 main(){
13     scanf("%d%d",&n,&k);
14     for(int i=1;i<=n;++i)scanf("%d",&Co[i]);
15     for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),
16         l[++ec]=fir[x],fir[x]=ec,to[ec]=y,
17         l[++ec]=fir[y],fir[y]=ec,to[ec]=x;
18     while(clock()<699999){
19         for(int i=1;i<=n;++i)re[i]=rand()%k;
20         for(int i=1;i<=n;++i)co[i]=re[Co[i]];
21         memset(dp,0x3f,sizeof dp);dfs(1,0);
22     }printf("%d\n",ans);
23 }

代码真好写。。。

T2:坏题

题意:给定n个长度不超过10的串,字符集大小为t。求有多少种两端都无限长的串,不与给定串匹配。两串相同当且仅当一个串下标全部+k后完全匹配。

多串匹配,八成AC自动机。

题意就是AC自动机上,从环出发到环结束,有多少方案。

对于非简单环,它就可以乱走了,方案数无穷。

对于一个环走到一个环再走到一个环,中间的环走几次是任意的,方案数也无穷。

看到一堆环环环的,那就写tarjan缩一下呗。然而我不会

对于简单环的判定,条件很简单:如果你是n个点的强联通分量,那么你就一定有至少n条边。

如果是恰好n条边,那么构造就明确了一定是一个简单环。否则多于n条边的话,你一定可以在图里提取出一个环,而在这环以外的边会使这个环上的点形成新的路径。

因为一个环已经强联通了,再连新的边一定会与环上对应两点的两条路径之一形成新的环,从而它就不是简单环了。

所以tarjan缩完之后,跑拓扑做dp就可以了。注意在tarjan时单个点无自环也会被判定为强联通分量,在dp时需要特殊处理。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 333333
 4 int c[S][7],fail[S],q[S],nt[S],t,qt,n,rt,pc,tim,scc,tp,ed[S],pt[S];
 5 int dfn[S],low[S],bl[S],ins[S],s[S],fir[S],l[S],to[S],ec;char ss[11];
 6 int FIR[S],L[S],TO[S],deg[S],EC,ans,dp[S][3];
 7 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
 8 void Link(int a,int b){L[++EC]=FIR[a];FIR[a]=EC;TO[EC]=b;deg[b]++;}
 9 void insert(int&p,int al){
10     if(!p)p=++pc;
11     if(!ss[al]){nt[p]=1;return;}
12     insert(c[p][ss[al]-‘a‘],al+1);
13 }
14 void bfs(){
15     q[1]=rt;for(int i=0;i<t;++i)c[0][i]=rt;
16     for(int h=1,qt=1;h<=qt;++h)for(int i=0;i<t;++i)
17         if(c[q[h]][i])fail[q[++qt]=c[q[h]][i]]=c[fail[q[h]]][i];
18         else c[q[h]][i]=c[fail[q[h]]][i];
19 }
20 void tarjan(int p){
21     dfn[p]=low[p]=++tim;s[++tp]=p;ins[p]=1;
22     for(int i=fir[p];i;i=l[i])if(!dfn[to[i]])tarjan(to[i]),low[p]=min(low[p],low[to[i]]);
23         else if(ins[to[i]])low[p]=min(low[p],low[to[i]]);
24     if(dfn[p]==low[p]){
25         bl[p]=++scc;ins[p]=0;
26         while(s[tp]!=p)ins[s[tp]]=0,bl[s[tp--]]=scc;tp--;
27     }
28 }
29 int main(){
30     scanf("%d%d",&t,&n);
31     for(int i=1;i<=n;++i)scanf("%s",ss),insert(rt,0);
32     bfs();for(int i=1;i<=pc;++i)for(int j=i;j;j=fail[j])nt[i]|=nt[j];
33     for(int i=1;i<=pc;++i)for(int j=0;j<t;++j)if(!nt[i]&&!nt[c[i][j]])link(i,c[i][j]);
34     tarjan(1);
35     for(int i=1;i<=pc;++i)pt[bl[i]]++;
36     for(int i=1;i<=pc;++i)for(int j=fir[i];j;j=l[j])if(bl[i]==bl[to[j]])ed[bl[i]]++;
37         else Link(bl[i],bl[to[j]]);
38     for(int i=1;i<=scc;++i)if(pt[i]!=ed[i]&&pt[i]>1)return puts("-1"),0;
39     for(int i=1;i<=scc;++i)if(!deg[i])q[++qt]=i;
40     for(int i=1;i<=scc;++i)if(pt[i]==ed[i])dp[i][0]=1;
41     for(int i=1;i<=scc;++i)if(pt[i]==ed[i])ans++;
42     for(int h=1;h<=qt;++h){
43         for(int i=FIR[q[h]];i;i=L[i]){
44             deg[TO[i]]--;
45             if(!deg[TO[i]]) q[++qt]=TO[i];
46             if(pt[TO[i]]==ed[TO[i]]) dp[TO[i]][1]+=dp[q[h]][0];
47             else dp[TO[i]][1]+=dp[q[h]][1],dp[TO[i]][0]+=dp[q[h]][0];
48         }
49         if(pt[q[h]]==ed[q[h]])ans+=dp[q[h]][1];
50     }
51     printf("%d\n",ans);
52 }

T3:不好不坏题

题意:求n以内的所有约数和是P倍数的数之和。$n<=10^{10}$,P为2或2017。

可能是因为我现在AC了所以我觉得它真是挺好的一道题。。。做得怪累的。

约数和是积性函数。所以我们拆解质因数进行考虑。

首先想P=2吧。分解质因数后,只要有一种质因子的贡献是偶数,那么它最终的质因数之和就是偶数,就会贡献答案。

「只要有一种就」这种限制条件不是很好考虑,来考虑相反的「一种都没有」

那就要求每种质因子的约数和都是奇数,这种数不会贡献答案。

对于同种质因子$p^e$它的约数和是$\sum\limits_{i=0}^{e} p^i$。除非p=2,这里每一项都是奇数。

那么只要有偶数项就好了,也就是质因子的指数必须是偶数。

那么质因子指数都是偶数的话,那么。。。不就是个平方数吗。。?

所以所有的平方数都不会贡献答案。

不太对。上面有一句「除非p=2」,还没有考虑呢。发现一个数不管有几个2它的因子和的奇偶性都不会变。

所以其实你不需要考虑2的次数,也就是2出现了奇数次也可以。

那么就是平方数的2倍也不会贡献答案。(不必再考虑4倍及更高,4倍不久已经就是平方数了吗,已经考虑过了)

然后这样就拿到了P=2的50分。接下来是P=2017。

线筛可以做,但是这做法显然没有扩展性(扩展成洲阁筛???)

首先我们惊奇的发现2017是一个良好的质数。

类似于上面的思路,我们还是分解质因数,如果任意一个质因数的贡献是2017的倍数,那么这个数就会产生贡献。

因为2017是质数所以不会出现由多个质因子加起来才能拼凑出2017的情况。

先考虑指数为1,那么其实就是(p+1)%2017==0,这种东西不会筛啊。

枚举有一定技巧啊,它肯定是2017的整倍数-1啊,而且它还必须是奇数。那么枚举就是以4033为首项,4034为公差。

这样的枚举量是$\frac{n}{4034}$的,对于最大的数据这个数大约是250万。然后。。。然后我只会根号筛了。

考虑指数为2,是$(p^2+p+1)%2017==0$。受到n的限制p不会超过$\sqrt{n}$,直接枚举就好了。

同理指数为3,打表发现其实只有229这一个p满足条件。在代码里我选择特殊处理了。

对于这些质数的次幂,它们的任意倍数的约数和都是2017的倍数,都会贡献答案,等差数列求和就好。

然后,到此为止,你就能得到80分的好成绩了。

但是,目前为止,你不仅跑的慢,在大数据下答案还是错的!

为什么?

举个例子,最小的1次幂质数是10121。数据范围超过$10^8$时,就可能会出现$10121^2$这种东西。

你刚才累加答案的时候,是把10121的倍数都加进去了,所以也会把这个数加进去。

但是积性函数只有在互质时才能满足乘法,所以你得到$10121^2$的质因数之和是错的。。。

二次幂与三次幂同理。但是最小的二次幂是2311,它的3次幂超过了最大的n。所以不必考虑。

唯一的三次幂229的4次幂还是有可能在n以内的,一定要记得考虑!

然后跨次幂相撞是不存在的,它们都超过了n的范围。所以只需要考虑一次幂数的平方和229的4次方即可。

容斥解决。

但是到了这里答案是对的,但是在最大数据下运行时间在15s以上。。。复杂度就卡在那个根号筛了。

然后其实需要的功能就是筛质数,然后看过数学一本通的我想到了Miller Rabin。然而我肯定不会写啊。

至少考后会了,而且也学会了快速乘。

然后抄一下LNC大神的Miller Rabin板子就好了。

等我彻底理解了就补充一下Miller Rabin与快速乘的草率讲解。

先说快速乘吧,它就是用来处理模数在long long级别的乘法。

考虑模法的实际含义$a \% b= a - \frac{a}{b} \times b$

而这里的问题是$xy \ mod \ b $。首先$\frac{xy}{b}$那一项好说,因为最后结果不大,所以直接用double算不会炸精。

然后$xy$与$\frac{xy}{b} \times b$的差值不超过b,也就是不会超过long long的范围,所以直接自然溢出。

你并不在意溢出的那些位,因为它差值不大,高位本来就不存在。

所以最后的流程就是$xy$乘法用unsigned long long自然溢出,减去用double算的除法强制转unsigned long long后乘b也自然溢出。

把两个自然溢出的数相减,就得到了最后的余数。

而有一种东西叫做$GongKai$优化(名字很高大上有没有?cbx发明的)。就是如果做乘法的两个数如果都没有超过$4 \times 10^9$,就用1ull做通常除法。

看起来非常蠢,但是强制转换和double类型很慢,在这道题里两种做法的常熟差了三分之一,还是很明显的。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 #define ll long long
 5 #define ull unsigned int
 6 #define S 30000005
 7 int P,pc,nc;bool np[S];ll num[S],pr[S],ans,n;const ll U=4000000000;
 8 ll mul(ll x,ll y,ll p){if(x<U&&y<U)return 1ull*x*y%p;ll z=(double)x/p*y,res=(unsigned ll)x*y-(unsigned ll)z*p;return (res+p)%p;}
 9 ll pow(ll b,ll t,ll M,ll a=1){for(;t;t>>=1,b=mul(b,b,M))if(t&1)a=mul(a,b,M);return a;}
10 bool isprime(ll x){
11     ll y=x-1,k=0;
12     if(x%3==0)return 0;
13     if(x%5==0)return 0;
14     if(x%7==0)return 0;
15     if(x%11==0)return 0;
16     while(!(y&1))++k,y>>=1;
17     for(int i=1;i<=2;++i){
18         ll z=rand()%(x-1)+1,d;z=pow(z,y,x);
19         for(int j=1;j<=k;++j){
20             d=mul(z,z,x);
21             if(d==1&&z!=1&&z!=x-1)return 0;
22             z=d;
23         }
24         if(d!=1)return 0;
25     }return 1;
26 }
27 ll C(ll x){ll t=n/x%mod;return t*(t+1)/2%mod*x%mod;}
28 main(){
29     scanf("%lld%d",&n,&P);
30     if(P==2){ans=(n%mod)*(n%mod+1)/2%mod;
31         for(ll i=1;i*i<=n;++i)ans=(ans-i*i)%mod;
32         for(ll i=1;i*i*2<=n;++i)ans=(ans-i*i*2)%mod;
33     }else{
34         for(int i=2;i<=100000;++i){
35             if(!np[i])pr[++pc]=i;
36             for(int j=1;j<=pc&&i*pr[j]<=100000;++j)
37                 if(i%pr[j]==0){np[i*pr[j]]=1;break;}
38                 else np[i*pr[j]]=1;
39         }
40         for(ll i=4033;i<=n;i+=4034)if(isprime(i))ans=(ans+C(i))%mod,num[++nc]=i;
41         for(int i=1;i<=nc&&num[i]<=n/10121;++i)for(int j=1;j<=i&&num[j]*num[i]<=n;++j)ans=(ans-C(num[i]*num[j]))%mod;
42         for(int j=1;1ll*pr[j]*pr[j]<=n;++j)if((1+pr[j]+1ll*pr[j]*pr[j])%2017==0)ans=(ans+C(1ll*pr[j]*pr[j]))%mod;
43         ans=(ans+C(229*229*229)-C(229ll*229*229*229))%mod;
44     }printf("%lld\n",(ans+mod)%mod);
45 }

好题啊

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12069900.html

时间: 2024-10-04 01:34:32

[考试反思]1219省选模拟3: 释怀的相关文章

[考试反思]0113省选模拟6:过载

真累啊...离上次放假也挺久,离下次放假也挺久,离上次放出去玩也挺久,离下次放出去玩还不知道有多久... 好累啊...大脑基本成天在挂机了.什么也不想干了... 持续状态不佳.但是今天运气好,所以考试排名看起来还可以. T1没认真读题也没看数据范围,以为是送分题,17分钟写完交了...然后我就把分送出去了 像个弱智一样...但是现在的精神状态的确不太能支持好好做题 幸亏T2是个比较简单的SAM+dp,思维量不大,脑子宕机的时候也能写一写. (归功于当时给大家讲课时稍微有一点理解,要是其它的板子我

[考试反思]0114省选模拟7:迷离

这次考得相对不错,但是没什么水准. 只不过记得T1这道原题而已.虽说我忘了怎么做,而且数据范围不一样...差不多是从头想的. 但是并没有AC,像个弱智一样,有两个细节写的完全不对还有80分运气也是真好. 其实挂了不止两个细节...以为是原题于是上来就写20分钟写完,然后过一会出一个锅... 然后看T2,感觉$O(nk^2)$也许差不多?常数很大...但也不会别的.挺好想但是不是很好写. 于是乎强烈谴责cbx没素质暴力水题考后还不改正解的无脸行径 于是就开始写,写了一个半小时. 看T3,绝对大神题

[考试反思]0117省选模拟10:争夺

T3出了一点锅,于是按IOI赛制打的. 可能也是这辈子唯一一次好好打的IOI赛制了. 提答,又沉里面了,进去就出不来.莫名的虚荣让我根本没有回头看传统题. 于是的确在T3的80%时间里一直单题rk1,然而其实很慌,剩下两道题又怎样? 运气好,T1特别水,T2数据水,T3用奇技淫巧多拿7分于是并列rk1了. 数组没清空丢了1分... 状态差的不行,一下午一道题都没改出来...咕到第二天也没改出来 于是在第二天考试的时候写完三个暴力之后终于把T2A了... 然后第二天考试就炸了,没什么好说的 T1:

[考试反思]0130省选模拟13:悔恨

0+30+20=50.rk8 关键在于: T1写错个变量名挂了100分 kxkxkxkx(激动的语无伦次) 考试过程?上来看T1,一个比较裸的基环树dp,断开环上一条边之后大概就是一个稍加改动的最大独立集. 思路不难想,细节倒是有一点,考场上调啊调啊过了样例又手模了各种数据都过了两个半小时之后很开心就扔了. 然后看T2/3啥都不会,写了俩随机化就走了. 然而T3随机化+贪心是可以AC的.正确性不知道...没写... 最后还有5分钟回T1,突然发现T1可以不是基环树而是基环树森林??? 啊修锅修锅

[考试反思]0220省选模拟27:怪异

怪异的一场考试.考的有点懵 $T1$正解是模拟,人人都能切,然而也没有多少人敢笃定这就是正解吧,常数和精度上下卡着,看运气的题了. $T2$想到了第二档分其实离正解就不远了但是时间不够没往下想.回$T1$卡常去了. $T3$不给状压分,于是猜到一条结论之后并不敢往下想... 然而最后$T1$也没有卡过,考后也在这破玩意上浪费了不少时间... 而且$T3$数据特别谁水暴力可以过,然而因为我不会决策点单调,所以学了学知识点,并没有用暴力水过... T1:飞行棋 大意:长度为$n$的序列,$m$人.每

[考试反思]0410省选模拟67:迷惑

现在想想,先做$T3$真乃人间迷惑行为. 部分分不多的一场考试,$T1$部分分最多结果没花时间光荣爆零,结果正解真的就是一个暴力+大力分类讨论 $T2$也比较可想,然而看着$75pts$的子任务心中有几分慌张,苟了个暴力跑路了. 结果一个弱智$T3$的$10pts$部分分$O(n^8)$暴写了$2.8k$.从这代码长度看是不是$10pts$您施舍的有点少啊. 其余部分分一点用没有,不知道咋想的. T1:链 大意:维护操作:加边,询问有几个点满足:删掉之后图中剩下的都是若干链.$n,m \le 2

[考试反思]0110省选模拟5:信仰

又倒一啦 10分真是个熟悉的成绩(虽然没有爆零熟悉) 状态一直低迷,没什么好说的 答题策略的话...就那样吧 一眼看出T1是结论题,没有部分分,不好写. 但T2是伯努利数的差不多是模板题了,于是就奔着它去了. 没有注意$0^0=1$.过不去样例最后交的暴力 没有抽时间认真打T3的暴力,因为至多30分. 因为现在30分和0分对我来说是一样的.我是要靠着省选翻盘,拿大众分的话肯定还是退役,求个稳,4个月白学. 现在的答题策略的确不能像联赛时一样了.现在求稳是赢不了了,在稳住200和争取230里我可能

[考试反思]0122省选模拟12:延迟

博客咕过了一年我也就忘了我考试状态了2333. T1是弱智题但是没想...写个暴力跑路了(时间不够,主要投在T2/3上了) 然而其实想到了一个乱搞,觉得能得分的概率不大,结果数据奇水完全不对的玩意还有20分,然而我并没有写... 然而T2写的是正解,虽说没有其他人的状压优秀,T了一个细节WA了一个拿了80分,凑合吧. 然后T3时间不多的时候写的,拿个暴力,想到了正解大概怎么写但是没有写,太恶心. 考后改题写了写,一下午就过去了...一晚上也就过去了...弄得跟我颓废了半天一样... 然而是真xx

[考试反思]0201省选模拟15:分界

30+10+30+100=170 rk13 17岁的第一仗出师不利. 和外校联考,所以难度不高?后三道题非常简单基本上都是裸的. 但是我做的这是个啥啊... T2广义后缀自动机板子写挂,如果儿子是nq就把儿子修改成nq... T3想到正解然后算错复杂度结果觉得都可以写个简单的于是就把暴力交了上去. T1猜到了第一个结论不会分块暴力也没想到数位dp... 考试前就感觉今天要炸,结果就真炸了. 又当了一次改题大神.半小时一道,中午没睡觉就直接改完了. 下午在uoj上乱跑找好题做ppt.效率挺低的.