zoukankan      html  css  js  c++  java
  • [考试反思]1018csp-s模拟测试79:荒谬

    对,如果你想把第5名粘进来,那么图片就是这么夸张。

    然而和我并没有什么关系,实在是太菜了。

    但是还是想吐槽出题人是真心没良心啊。。。做了达哥的良心题之后眼光极其挑剔

    这套题的部分分设置非常愚蠢,唯一一个可用的部分分在T2,但是T2说的还很不清楚。

    T2其实已经完成了最艰难的转化题意,但是最后败在了细节上。

    T1也基本上是全场切,结果出锅了。

    我想问一个问题啊:在时间比较紧的情况下,是应该打完题就打对拍,还是优先往下做题啊?

    skyh就是没脸。去厕所遇到他的话我这场绝对炸。

    发现T2题意前遇到的

    我:我估计我60分

    FACEFACE:那我肯定不止60分了。我发现T2的题意了,难题。

    然后我差点就弃T2了,差点就只剩下50分了。。。

    T1暴力弹栈暴力恢复,结果恢复的时候往栈里应该是倒序加,而不应该是正序。。。挂70

    T2计算$C_n^3$时没除6锅了20分。

    。。。

    心情稍低沉。越发感觉自己像个傻子。

    会题不一定不是傻子。

    拿不到分那就是个傻子。。。

    吸取教训吧。。。

    对拍。要对拍。就你那个程度不打对拍肯定锅。

    T1:树

    因为我蠢所以没想到正解。考场上维护了一个单调栈,然后离线暴干。

    会被蒲公英图/扫帚图干掉成$O(n^2)$。但是出题人保证数据随机。我没打正解我没脸。

    正解很简单,按照递减序建树,倍增乱搞就行。没心情打了。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<vector>
     5 using namespace std;
     6 vector<int>anc[100005],c[100005],id[100005],tmp[100005];
     7 int fir[100005],l[200005],to[200005],cnt,n,q,w[100005],dep[100005];
     8 int sta[100005],top,sdep[100005],sw[100005],ans[100005];
     9 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
    10 bool com(int a,int b){return a>b;}
    11 void dfs(int p,int fa){
    12     dep[p]=dep[fa]+1;
    13     while(top&&sw[top]<=w[p])top--,tmp[p].push_back(sta[top+1]);
    14     sta[++top]=p;sw[top]=w[p];sdep[top]=dep[p];
    15     for(int i=0;i<id[p].size();++i){
    16         int ed=lower_bound(sw+1,sw+1+top,c[p][i],com)-sw,st=lower_bound(sdep+1,sdep+1+top,dep[anc[p][i]])-sdep;
    17         ans[id[p][i]]=max(0,ed-st);
    18     }
    19     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p);
    20     top--;
    21     for(int i=(int)tmp[p].size()-1;~i;--i)sta[++top]=tmp[p][i],sw[top]=w[sta[top]],sdep[top]=dep[sta[top]];
    22 }
    23 int main(){
    24     scanf("%d%d",&n,&q);
    25     for(int i=1;i<=n;++i)scanf("%d",&w[i]);
    26     for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),link(x,y),link(y,x);
    27     for(int i=1,u,v,C;i<=q;++i)scanf("%d%d%d",&u,&v,&C),anc[u].push_back(v),c[u].push_back(C),id[u].push_back(i);
    28     dfs(1,0);
    29     for(int i=1;i<=q;++i)printf("%d
    ",ans[i]);
    30 }
    View Code

    T2:环circle

    其实虽说题目说的很不清楚,但是还是有很多提示的。

    能从题目里隐隐约约得出以下信息:

    竞赛图,环,最小。

    看一眼数据范围,最小暴力分是n=300。这个只能是$O(n^3)$的复杂度了。

    再把第一个样例的16个图都画出来,不难发现它要的就是三元环计数,不分起点。

    求证:竞赛图如果有环,那么最小环一定是三元环

    证明:

    如果存在一个大于3元的环,那么对于其中任意距离大于等于2的两个点ab,在环上已经存在了一个顺时针和一个逆时针路径。

    这时候因为图是竞赛图,ab两点之间也必须直接有边,这一条边能和顺时针路径或逆时针路径之一形成一个环。

    这个环小于原来的环。这样的话大环会不断被分割成小的。直到环中不存在距离大于等于2的点,那么就只剩下了一个三元环。

    证毕。

    那么就是求三元环数量了。

    30分:n<=300。

    暴力枚举三个点。看贡献。

    如果你一条边都不知道,那么可能形成2种环,一共$2^3=8$种情况,期望贡献1/4。

    如果你只知道一条边,那么只能形成1种环,一共$2^2=4$种情况,期望贡献1/4。

    如果你知道两条边,这两条边指向或背向同一个点,那么贡献是0,否则贡献1/2。

    如果你三条边都知道。。。那就不用我说了吧。。。贡献0或1

    +20分:e=0

    全都是三条边都不知道的情况,是$frac{1}{4} imes C_n^3$

    +20分:e=n*(n-1)/2

    全都是三条边都知道的情况,但是不能$n^3$枚举。

    因为e<=1000000,所以可以知道n<=1500。

    bitset枚举(也可以不用)。大力讨论。

    100分:

    考虑容斥。先让所有边都产生贡献。

    然后产生负贡献的就是不合法的三元环:有两条边从同一个点指出。

    然后考虑期望有多少这样的环。

    枚举所有这样的点,考虑每一条不确定的边。

    如果$p_i$表示这个点i有几条出边,有$q_i$条未知边。

    答案减去$C_{p_i}^2 + frac{C_{q_i}^2}{4} + frac{p_i imes q_i}{2}$

     1 //可以证明,竞赛图只要存在环,那么最小的环大小一定是3
     2 //所以问的就是图中期望有几个三元环
     3 #include<cstdio>
     4 #include<vector>
     5 using namespace std;
     6 vector<int>in[1555],out[1555];
     7 #define qtr 250000002ll
     8 #define hlf 500000004ll
     9 #define mod 1000000007ll
    10 int pow(long long b,int t,long long a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
    11 int graph[1555][1555],n,e;long long ans;
    12 int main(){
    13     scanf("%d%d",&n,&e);
    14     if(e==0){
    15         printf("%lld
    ",qtr*n%mod*(n-1)%mod*(n-2)%mod*pow(6,mod-2)%mod);
    16     }else if(n<=300){
    17         for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),graph[x][y]=1,graph[y][x]=-1;
    18         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)for(int k=j+1;k<=n;++k)
    19             if((graph[i][j]!=0)+(graph[j][k]!=0)+(graph[i][k]!=0)<=1)ans+=qtr;
    20             else if(graph[i][j]==1&&graph[j][k]==1&&graph[k][i]==1)ans++;
    21             else if(graph[i][j]==-1&&graph[j][k]==-1&&graph[k][i]==-1)ans++;
    22             else if(graph[i][j]==1&&graph[j][k]==1&&graph[k][i]==0)ans+=hlf;
    23             else if(graph[i][j]==-1&&graph[j][k]==-1&&graph[k][i]==0)ans+=hlf;
    24             else if(graph[i][j]==1&&graph[j][k]==0&&graph[k][i]==1)ans+=hlf;
    25             else if(graph[i][j]==-1&&graph[j][k]==0&&graph[k][i]==-1)ans+=hlf;
    26             else if(graph[i][j]==0&&graph[j][k]==1&&graph[k][i]==1)ans+=hlf;
    27             else if(graph[i][j]==0&&graph[j][k]==-1&&graph[k][i]==-1)ans+=hlf;
    28         printf("%lld
    ",ans%mod);
    29     }else if(e<<1==n*(n-1ll)){
    30         for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),graph[x][y]=1;
    31         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)if(graph[i][j])out[i].push_back(j);else in[i].push_back(j);
    32         for(int i=1;i<=n;++i)for(int j=0;j<out[i].size();++j)for(int k=0;k<in[i].size();++k)ans+=graph[out[i][j]][in[i][k]];
    33         printf("%lld
    ",ans%mod);
    34     }
    35 }
    部分分打满
     1 //可以证明,竞赛图只要存在环,那么最小的环大小一定是3
     2 //所以问的就是图中期望有几个三元环
     3 #include<cstdio>
     4 #include<vector>
     5 using namespace std;
     6 #define qtr 250000002ll
     7 #define hlf 500000004ll
     8 #define six 166666668ll
     9 #define mod 1000000007ll
    10 int pow(long long b,int t,long long a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
    11 int p[100005],q[100005],n,e;long long ans;
    12 int main(){
    13     scanf("%d%d",&n,&e);
    14     ans=1ll*n*(n-1)%mod*(n-2)%mod*six%mod;
    15     for(int i=1,x,y;i<=e;++i)scanf("%d%d",&x,&y),p[x]++,q[y]--,q[x]--;
    16     for(int i=1;i<=n;++i)q[i]+=n-1;
    17     for(int i=1;i<=n;++i)ans=(ans-p[i]*(p[i]-1ll)/2-1ll*p[i]*q[i]%mod*hlf%mod-q[i]*(q[i]-1ll)/2%mod*qtr%mod+mod)%mod;
    18     printf("%lld
    ",ans);
    19 }
    AC

    T3:礼物gift

    $C_{a_i + b_i + a_j + b_j}^{a_i + a_j}$

    $=sumlimits_{t=0}^{a_i + a_j}C_{a_i +b_i}^{t} imes C_{a_j + b_j}^{a_i + a_j -t}$

    $=sumlimits_{t=-a_i}^{a_j}C_{a_i +b_i}^{t + a_i} imes C_{a_j + b_j}^{a_j -t}$

    $=sumlimits_{t=-a_i}^{b_i}C_{a_i +b_i}^{t + a_i} imes C_{a_j + b_j}^{a_j -t}$

    然后就可以发现两部分式子已经分别只与i和j有关了。

    带j的那一项关于t开一个桶,然后每次加一个新物品时先枚举t查找桶里的值,再往桶里放一下。

    注意贡献答案时t的枚举范围与更新桶时的t的枚举范围是完全相反的。

    拆开两部分分别算,改变枚举范围。这是这道题的难点。

     1 #include<cstdio>
     2 #define mod 1000000007
     3 int fac[20000005],invv[20000005],inv[20000005],n,BUC[40000005],*buc=BUC+20000002,ans;
     4 int Mod(int p){return p<mod?p:p-mod;}
     5 int C(int b,int t){return (t<0||t>b)?0:1ll*fac[b]*inv[b-t]%mod*inv[t]%mod;}
     6 main(){
     7     fac[0]=fac[1]=invv[1]=inv[0]=inv[1]=1;
     8     for(int i=2;i<=20000000;++i)fac[i]=1ll*fac[i-1]*i%mod,invv[i]=mod-1ll*mod/i*invv[mod%i]%mod,inv[i]=1ll*inv[i-1]*invv[i]%mod;
     9     scanf("%d",&n);
    10     for(int i=1,a,b;i<=n;++i){
    11         scanf("%d%d",&a,&b);
    12         for(int t=-a;t<=b;++t)ans=Mod(ans+1ll*buc[-t]*C(a+b,a+t)%mod);
    13         for(int t=-b;t<=a;++t)buc[-t]=Mod(buc[-t]+C(a+b,a-t));
    14     }printf("%d
    ",Mod(ans<<1));
    15 }
    View Code
  • 相关阅读:
    只有经历过,才知道苦痛的来源,而时间,将是唯一验证坚持是否值得的标准
    java返回值是list的时候获取list的参数类型
    spring4整合xfire1.2.6的问题解决
    基于tomcat插件的maven多模块工程热部署(附插件源码)
    新鲜出炉的jquery fileupload 插件
    WEB应用打成jar包全记录
    activiti5.14版本在线流程设计器的国际化中文支持
    activiti获取可回退的节点
    园子里的生活
    2022届我校高二下半期理科12题
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11702739.html
Copyright © 2011-2022 走看看