[考试反思]0323省选模拟53:常数

服气了。$T1$被卡常了。

出题人你卡常就卡常吧,但是能不能不要绑着子任务卡啊。

你绑子任务就绑子任务但是你好歹给被卡常的留一档分别直接卡成和$n^2$一样啊。

你卡就卡了能不能直接把最后一个子任务设成$63pts$啊。

这题被你卡常一下正常考试一半多的分数就没了。

算了出题人向来不考虑答题的感受,自己没被卡于是就卡别人呗。

本来大概是$120pts$大概也能混个前三,真有意思。

然后$T3std$还是巨型毒瘤$whzzt$写的,大力卡常,考后浪费了不少时间。。。

毒瘤,真毒瘤

T1:数(number)

大意:求$n$位的可以有前导$0$的回文的奇数位上数字和等于偶数位上数字和的数的个数。$T \le 10,n \le 10^6$

我还寻思这这玩意多测是要闹哪样,原来是卡常啊。。。

$dy$原题。思路不难。

按照$n \ mod \ 4$分类讨论,偶数直接乱填一半剩一半对称。

余$1$那么就枚举中间这一位是几然后两边的差确定,奇数位加偶数位减,和为$0$

把偶数位减$x$改为偶数位$+9-x$。就可以插板容斥组合数了。

余$3$大概也一样,枚举中间两位,但是需要记忆化,否则常数肯定升天。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 #define S 2750001
 5 map<int,int>M[S];
 6 int fac[S],inv[S],t,n;
 7 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 8 int C(int b,int t){return t<0||t>b?0:1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;}
 9 int cal(int n,int v){
10     v=abs(v);
11     if(!n)return v?0:1;
12     if(M[n][v])return M[n][v];int rn=n,rv=v;
13     v+=n*9;int ans=0;n<<=1;
14     for(int i=0;v>=0;++i,v-=10)ans=(ans+(i&1?-1ll:1ll)*C(n,i)*C(v+n-1,n-1))%mod;
15     return M[rn][rv]=(ans+mod)%mod;
16 }
17 int main(){
18     for(int i=fac[0]=1;i<S;++i)fac[i]=1ll*fac[i-1]*i%mod;
19     inv[S-1]=qp(fac[S-1],mod-2);
20     for(int i=S-2;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod;
21     cin>>t;while(t--){cin>>n;
22         if(n%2==0)cout<<qp(10,n/2)<<endl;
23         else if(n%4==1){
24             int ans=0;
25             for(int i=0;i<5;++i)ans=(ans+cal(n/4,i))%mod;
26             cout<<ans<<endl;
27         }else{
28             int ans=0;
29             for(int i=0;i<5;++i)for(int j=0;j<=9;++j)ans=(ans+cal(n/4,i-j))%mod;
30             cout<<ans<<endl;
31         }
32     }
33 }

T2:序列

大意:给定序列,要求重新排列后奇偶相间,一种方案的代价为所有数字交换前后坐标差绝对值,最小化代价的基础上最小化新序列字典序。$n \le 10^5,a_i \le 10^9$

大概是个贪心。发现最小代价一定是所有奇数元素内部顺序不变,偶数同理。

奇数偶数可以分开讨论了。最后一起合并就行。

除了内部顺序不变,我们可以发现如果元素$a,b$对应的新位置是$p_a,p_b$,有$a<b\le p_a < p_b$那么其实$a$可以到$p_b$上,$b$可以到$p_a$上

同理,大小于号反过来也成立。

这样,更广泛的结论是:对于一个极长的变化方向相同的段,以$a<p_a$为例,那么$a$其实可以填在任意$p_i>a$

那么就可以草率的贪心,对于每个极长同向段,扫描线扫一下,遇到$p_a$就加入堆,遇到$a$就取最值使字典序尽量小。复杂度$O(nlogn)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 111111
 4 int a[S],n,t,p[S],ans1[S],ans2[S],c,C,c1,c2;
 5 void pt(int*a){for(int i=1;i<=n;++i)printf("%d ",a[i]);}
 6 priority_queue<int>q; map<int,int>M;
 7 void solve(int*A,int s,int t,int o){
 8     if(o){
 9         int p1=s,p2=s;
10         while(p1<=t||p2<=t){
11             while(p[p1]<=p2&&p1<=t)q.push(-a[p[p1]]),p1+=2;
12             while((p1>t||p2<p[p1])&&p2<=t)A[p2]=-q.top(),q.pop(),p2+=2;
13         }
14     }else{
15         int p1=t,p2=t;
16         while(p1>=s||p2>=s){
17             while(p[p1]>=p2&&p1>=s)q.push(a[p[p1]]),p1-=2;
18             while((p1<s||p2>p[p1])&&p2>=s)A[p2]=q.top(),q.pop(),p2-=2;
19         }
20     }
21 }
22 void work(int t,int*A){
23     c=-1;C=0;for(int i=1;i<=n;++i)if(a[i]&1^t)p[c+=2]=i;else p[C+=2]=i;
24     for(int i=1,d;d=i>=p[i],i<=n;)for(int j=i;;j+=2)if(j>=p[j]^d||j>n){solve(A,i,j-2,d);i=j;break;}
25     for(int i=2,d;d=i>=p[i],i<=n;)for(int j=i;;j+=2)if(j>=p[j]^d||j>n){solve(A,i,j-2,d);i=j;break;}
26 }
27 int main(){
28     cin>>n;
29     for(int i=1;i<=n;++i)scanf("%d",a+i),t+=a[i]&1,M[a[i]]=i;
30     if(n&1)work(t<n-t,ans1),pt(ans1);
31     else{
32         work(0,ans1);work(1,ans2);
33         for(int i=1;i<=n;++i)c1+=abs(i-M[ans1[i]]),c2+=abs(i-M[ans2[i]]);
34         if(c1!=c2)return pt(c1<c2?ans1:ans2),0;
35         for(int i=1;i<=n;++i)if(ans1[i]!=ans2[i]){pt(ans1[i]<ans2[i]?ans1:ans2);break;}
36     }
37 }

T3:烤仓鼠

大意:$n$组人分$m$个东西,不能劈开,每组有$a_i$人。最小化$d$,满足任意两人分到的数目差$\le d$,任意两组分到的总数差$\le d$。

要求构造方案。(输出每组的数量)。$n \le 10^6,\sum a_i \le 10^9,m\le 10^{18}$

先不说构造方案,先求$d$。这个东西当然有单调性,所以可以采取二分答案。问题在于检查是否合法。

首先,明显的是,如果把所有组按照人数排序,那么一定存在一组最优解满足前面的组分到的数量小于等于后面的组。

我们设每个人至少分到$x$个,那么第一组的最大数量应该就是$a[1] \times (x+d)$。其余组虽然人数比他们多,但总数最多只能比它们多$d$

还要注意,对于所有人数和第一组相同的组它们的上届也和第一组一样。

组之间相互独立没有影响。那么我们能得到,所有组的上届之和,也就是我们最多可以发放多少物品:

$maxsum=(a[1] \times same1) \times (x+d) + ( (a[1] \times (n-same1 ) \times (x+d) + (n-same1 ) \times d ) $

而我们又知道如果$maxsum<m$那么一定无解。

于是我们移项让$x$做主元,就能得到$x$的上届:$x \le \lceil \frac{ m-(a[1] \times n + (n-same1) \times d) }{a[1] \times n} \rceil$

当然如果给每个人都分配$x$就直接超过了$m$那么直接非法。当然$x$也要对$0$取$max$

我们现在知道物品一定不会出现分不完的情况(因为$x$已经保证总数小于上届了)。问题就是:够不够分,以及每组是否能合法。

按照上面排序的说法,第$n$组分到的一定是最多的,其它组都不会超过它。

而最后一组的下界是$a[n]\times x$故其它各组的下界之一就是$\ge a[n] \times x -d$

当然对于第$i$组而言还有一个下界是$\ge a[i] \times x$。两个下届取$max$就是当前组真正的下界。

然后当前组的上界也很简单:如果它的人数和第一组一样多,那么上届就是$a[1] \times (x+d)$否则就是$a[1] \times (x+d) + d$

(其实应该和$a[i] \times (x+d)$取$min$但是既然$a[i]-a[1] \ge 1$那么明显后面这个界就被前面包含了。

所以对于每个组,如果下界$>$上界那么自然无解。

同时,如果下界之和大于$m$了那么就不够分了,也是无解。

在满足上述所有要求的情况下,每组都有一个合法区间,且总和区间也包含$m$。

那么就一定存在一种方案来给每个组分物件。组内分物件那就更简单了。

(不必再考虑人与人之间的限制,因为我们在限制组的时候,人的上下界也已经用$[x,x+d]$卡住了,所以组合法人也一定合法)

所以满足上述条件就一定存在合法方案。就这样就可以二分了,时间复杂度$O(nlogm)$。

然后是构造方案。这个比较神奇。

首先如果最后$d=0$那么方案就可以直接输出了。

这条卡常理论上当然可以不加,但是无良出题人在$std$里加了,然后就拿来卡你常数了,所以你也必须加。

首先我们对于一个确定的$d$我们依旧可以解出一个$x$。

然后我们还是可以按照上面的方式得到每个组的上下界。

我们首先给每个组都分若干东西直至每个组都达到上届,这时候很可能不够分,于是我们先设为上界,然后再往回要。

首先我们当然可以把某些突出的组压下来:再不低于这个组的下届的情况下,每个组的数量都下压至$a[i] \times (n+d)$。

(也相当于在尽量缩小组间极差使之合法,现在组差一定$\le d$因为最小的也是$a[i] \times (n+d)$。如果有的组超过这个值$+d$那么一定非法)

既然组之间已经合法了,那么接下来我们就可以把所有组同时下调相同数目,一定依旧合法。

但是下降数目不能超过剩余总下降量,也不能使某个组下降到下届以下,同时下降量还应该是$d$的整数倍,表示分的最多的人变成最少的,方便处理。

(这里为了节约常数,不突破下届,可以直接对$mx[n]-mn[n]$取$mn$。因为$n$的下界一定是最大的,而上界又被压平了,所以一定是限制的最紧的)

再接下来,如果下降的还不够,我们考虑继续下调。这时候,我们的下调幅度不能超过$d$,这样依旧能保证下降之后仍然合法。

(其实也一定不会超过$d$,因为上面已经保证了所有组同时下降,就说明,要么是不够让你下降那么多,要么是触及了某些组的下界)

当然下降幅度依旧不能突破每组的下届。当然这里应该倒着扫。不需要继续下降就跳出。才可以保证合法。

这样一轮下降之后,如果依旧还是需要下降,我们就能确定:一定是某些组触及了下界。(应该是后面的组,下界较高)

而我们又知道,我们的这个$d$保证有解,所以我们只要倒着再扫一遍,把遇到的组都拍到下界就行了。

按照道理来讲这个构造只是线性的扫了若干遍,理论上讲是$O(n)$的。

但是其实这里的常数,肉眼可见的大:乘除膜以及好多好多$min,max$。本来$n=10^6$就不小了。

然后出题人还有意卡你,让你直接飞升到$12s$。所以$d=0$的那条特判是有必要加的。。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 1111111
 4 long long m,n,a[S],sum[S],same1,o[S],R[S],mn[S],mx[S];
 5 bool chk(long long d){
 6     // MAX_SUM = (a[1]*same1)*(x+d) + [ (a[1]*(n-same1))*(x+d) + (n-same1) * d ]
 7     // = a[1]*n*(x+d) + d * (n-same1)
 8     // = a[1]*n*x + ( a[1]*n + ( n-same1 ) )*d
 9     // MAX >= m
10     // x<= [ m - ( a[1]*n +(n-same1) )*d ]  /  (a[1]*n) {ceil}
11     long long x=max(0.,ceil((m-(1.*a[1]*n+(n-same1))*d)/a[1]/n)),MIN_SUM=sum[n]*x;
12     if(x>m/sum[n])return 0;
13     for(int i=1;i<=n&&MIN_SUM<=m;++i)
14         if( max(a[i]*x,a[n]*x-d) > 1.*a[1]*(x+d)+(a[i]==a[1]?0:d)) return 0;//MIN_GROUP > MAX_GROUP
15         else MIN_SUM+=max((a[n]-a[i])*x-d,0ll);//Can not be less than a[n]*x-d,so add (a[n]*x-d) - (a[i]*x)
16     return MIN_SUM<=m;
17 }
18 void solve(long long d){
19     if(!d){for(int i=1;i<=n;++i)printf("%lld ",m/n);return;}
20     long long x=max(0.,ceil((m-(1.*a[1]*n+(n-same1))*d)/a[1]/n)),tot=0,w,MN=a[1]*(d+x);
21     for(int i=1;i<=n;++i)mn[i]=max(a[i]*x,a[n]*x-d),mx[i]=a[1]*(x+d)+(a[i]!=a[1]?d:0),tot+=mx[i];//init to max
22     for(int i=n;i&&tot!=m;--i)w=min(mx[i]-max(mn[i],MN),tot-m),mx[i]-=w,tot-=w;//make it legel when a[1] is at its max
23     if(d){long long T=min((tot-m)/n,mx[n]-mn[n])/d*d;if(T)for(int i=n;i;--i)mx[i]-=T,tot-=T;}//decrease averangely,still legel
24     MN=min(mx[n]-mn[n],d);//cannot decrease more than d.
25     for(int i=n;i&&tot!=m;--i)w=min(min(mx[i]-mn[i],MN),tot-m),tot-=w,mx[i]-=w;
26     for(int i=n;i&&tot!=m;--i)w=min(mx[i]-mn[i],tot-m),tot-=w,mx[i]-=w;
27     for(int i=1;i<=n;++i)printf("%lld ",mx[R[i]]);
28 }
29 char buffer[S],*s,*t;
30 #define getchar() ((s==t&&(t=(s=buffer)+fread(buffer,1,S,stdin),s==t))?EOF:*s++)
31 int read(){
32     register int p=0;register char ch=getchar();
33     while(ch<‘0‘||ch>‘9‘)ch=getchar();
34     while(ch>=‘0‘&&ch<=‘9‘)p=(p<<3)+(p<<1)+ch-‘0‘,ch=getchar();
35     return p;
36 }
37 int main(){//freopen("hamster6-1.in","r",stdin);freopen("0.out","w",stdout);
38     cin>>n>>m;
39     for(int i=1;i<=n;++i)a[i]=read(),o[i]=i;
40     sort(o+1,o+1+n,[](int x,int y){return a[x]<a[y];}); sort(a+1,a+1+n);
41     for(int i=1;i<=n;++i)R[o[i]]=i;
42     for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i],same1+=a[i]==a[1];
43     long long l=0,r=m,ans;
44     while(l<=r)if(chk(l+r>>1))r=ans=l+r>>1,r--;else l=(l+r>>1)+1;
45     cout<<ans<<endl;solve(ans);
46 }

也可以参照一下代码及注释

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

时间: 2024-10-16 00:57:14

[考试反思]0323省选模拟53:常数的相关文章

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

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

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

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

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

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

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

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

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

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

[考试反思]0306省选模拟39:延续

俩原题.对于看视频课太匆忙的我来说,还是算俩新题吧. 为啥感觉最近总是考第$9$啊.最近这种名次的频率好高.. (好菜啊第$9$还学个啥呢啊脑子呢???这还翻个什么盘啊) 然而其实第$9$也是混来的. 最开始先看的$T1$发现好像是原题,但是印象不深,大概还记得第一步怎么做. 接着往后看,$T2$看起来像弱智题.$T3$的话又是原题,思路极其简单但是是$exSAM+LCT$写出来会暴毙.于是扔在最后. 然后回$T1$尝试回忆.然后就没有然后了.折腾来折腾去想了两个小时硬是没想到$dp$定义. 果

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

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

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

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

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

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