zoukankan      html  css  js  c++  java
  • [考试反思]0209省选模拟22:谬误

    感觉自己被上天嘲讽了一样。。。联赛后拿的好名次都是通过一些奇奇怪怪的原因。

    上次是毒瘤打表被我碰上了,这次是数据水乱打能拿好多分(刚开始)

    但是大体也还行后两题都写对拍了,还都发现锅了

    只不过当时没有好好学manacher导致考场上并没有打出来,所以就只写了暴力。

    然后也就没啥了,对拍都挂上了,也就没啥说的

    只不过T1高的出乎意料了,于是找教练加了两三组数据把自己$hack$掉。

    应该像$NC$说的那样加个20组的这样我就能大概看到真正的名次了。T1其实得10分也就差不多了。

    然而自己加的几组数据其实还不够毒瘤。。。可以hack一部分正解。。。

    T1:遮天蔽日

    大意:点光源照圆,中间有个不透明多边形,多边形会绕重心自转,绕圆形公转,给定时刻,求圆被照射到的弧长。

    题目的本意是好的,但是写起来是真的恶心。

    看着$std$大概写了下来,其实很好理解,也并没有想象中那么恶心。

    首先先按照题意公转自转。先后顺序无所谓,但是共转并不能让所有点都公转,而是让重心公转,点的相对位置不变。

    问题是求重心:类似加权平均数的样子,所有点向原点连线,然后做一个带正负的三角剖分,重心坐标即为两点坐标按照面积加权后/3。

    skyh说的:感性理解+记个板子足够用了。

    然后所有点与光源连线,再连上俩切线,这些直线按照极角排序。

    为了方便,我们设靠下的直线的极角为基准值0,其余均与之做差。先把范围外的都干掉。

    然后现在讨论的就是两条切线之间的线。

    对于每两条线之间的部分,这段区域要么全亮要么全不亮,所以我们从中任选一个角度。

    暴力枚举多边形所有边,用向量判断是否有交点即可。

    计算切线用到了正弦定理。最后算弧长的时候,实际上为了方便,我们求的是0~x这段角度所对应的圆心角大小。

    然后询问某一段的时候相当于一个差分。

    具体计算这个值的话,是点与圆心连线后再去用正弦定理计算圆心角。

    只需要一个完整的向量桶,然后就按照直觉来。

    代码写出二义性了,调到暴毙,原理不明。

    我写的这个不会被凹多边形$hack$。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const double pi=3.1415926535,Pi=2*pi;
     4 struct P{
     5     double x,y;
     6     P():x(0),y(0){}
     7     P(double X,double Y):x(X),y(Y){}
     8     P operator+(P b){return P(x+b.x,y+b.y);} P&operator+=(P b){x+=b.x;y+=b.y;}
     9     P operator-(P b){return P(x-b.x,y-b.y);} P&operator-=(P b){x-=b.x;y-=b.y;}
    10     P operator*(double b){return P(x*b,y*b);} P&operator*=(double b){x*=b;y*=b;}
    11     P operator/(double b){return P(x/b,y/b);} P&operator/=(double b){x/=b;y/=b;}
    12     double operator*(P b){return x*b.x+y*b.y;} double operator^(P b){return x*b.y-b.x*y;}
    13     double len(){return sqrt(x*x+y*y);} double A(){return atan2(y,x);}
    14     P spin(double A){return P(x*cos(A)-y*sin(A),x*sin(A)+y*cos(A));}
    15 }S,E,p[33],G;
    16 int n,Ac;double t1,t2,t,R,area,lenSE,dA,lwr,A[33],ans;
    17 double cal(double a){double A=(a-dA/2);return asin(max(-1.,min(1.,sin(A)/R*lenSE)))-A;}
    18 int main(){
    19     cin>>S.x>>S.y>>E.x>>E.y>>R>>n>>t1>>t2>>t;
    20     lenSE=(E-S).len(); dA=asin(R/lenSE)*2; lwr=(E-S).A()-dA/2; 
    21     if(lwr<-pi)lwr+=Pi; if(lwr>pi)lwr-=Pi;
    22     for(int i=0;i<n;++i)cin>>p[i].x>>p[i].y;
    23     for(int i=0;i<n;++i)G+=(p[i]+p[(i+1)%n])*(p[i]^p[(i+1)%n]),area+=p[i]^p[(i+1)%n];
    24     G/=3*area;for(int i=0;i<n;++i)p[i]-=G;
    25     t1=t/t1*Pi;t2=t/t2*Pi;
    26     G=E+(G-E).spin(t1); for(int i=0;i<n;++i)p[i]=G+p[i].spin(t2);
    27     A[++Ac]=0; A[++Ac]=dA;
    28     for(int i=0;i<n;++i)A[++Ac]=(p[i]-S).A()-lwr;
    29     for(int i=1;i<=Ac;++i)if(A[i]<-pi)A[i]+=Pi;else if(A[i]>pi)A[i]-=Pi;
    30     sort(A+1,A+1+Ac);
    31     for(int i=1,ok;ok=1,i<Ac;++i)if(A[i]>=0&&A[i]<dA&&A[i+1]-A[i]>1e-7){
    32         P tmp=P(cos((A[i+1]+A[i])/2+lwr),sin((A[i+1]+A[i])/2+lwr)),x,y;
    33         for(int j=0;j<n;++j)if((((x=p[j])-S)^tmp)*(((y=p[(j+1)%n])-S)^tmp)<0){
    34             y-=x;double rate=(y^(S-x))/(tmp^y);
    35             if(rate>0&&(S+tmp*rate-E)*(S-E)>0){ok=0;break;}
    36         }if(ok)ans+=cal(A[i+1])-cal(A[i]);
    37     }printf("%.2lf
    ",ans*R);
    38 }
    View Code
     1 0 0 100 0 5
     2 12 1 1 0
     3 90 1
     4 90 100
     5 110 100
     6 110 -100
     7 90 -100
     8 90 -1
     9 89 -4
    10 89 -111
    11 111 -111
    12 111 111
    13 89 111
    14 89 4
    凹的数据

    T2:三元组

    大意:给定字符串求所有满足$i le j < k$且$S(i,j),S(j+1,k)$都是回文串的$sum ik$。多测。$|S| le 10^6, T le 5$

    很明显在卡$O(nlogn)$。

    线性回文串就$manacher$。需要维护以点$i$为左端点的回文串的右端点编号和。区间加等差数列。

    问题是离线的,也就是询问都在修改后。维护两个数组$a,b$表示位置$i$往后要加上以$b[i]$为首项$a[i]$为公差的等差数列。

    最后做前缀和就行了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 2222222
     4 #define mod 1000000007
     5 char s[S];int R[S],C,mR=-1,ans,a[S],b[S],c[S],d[S];
     6 void add(int&x,int y){x+=y;if(x<0)x+=mod;if(x>=mod)x-=mod;}
     7 int main(){s[0]='_';//freopen("3.in","r",stdin);freopen("3.out","w",stdout);
     8     int t;cin>>t;while(t-->0){
     9         scanf("%s",s+1);int n=strlen(s+1);mR=-1;
    10         for(int i=n;i;--i)s[i<<1]=s[i],s[i]=0;
    11         for(int i=1;i<n+1<<1;++i){
    12             R[i]=i<=mR?min(mR-i+1,R[2*C-i]):0;
    13             while(s[i+R[i]]==s[i-R[i]])R[i]++;
    14             if(i+R[i]>mR)mR=i+R[i]-1,C=i;
    15         }
    16         for(int i=1;i<n+1<<1;++i)R[i]--;
    17         for(int i=1;i<n+1<<1;++i){
    18             int l=(i-R[i]>>1)+1,r=i+R[i]>>1,md=l+r>>1;
    19             if(r>=l)a[md+(i&1)]--,a[r+1]++,add(b[md+(i&1)],md),add(b[r+1],1-l);
    20         }
    21         for(int i=1;i<=n;++i)c[i]=b[i],add(b[i+1],b[i]+a[i]),a[i+1]+=a[i],a[i]=b[i]=0;
    22         for(int i=1;i<n+1<<1;++i){
    23             int l=(i-R[i]>>1)+1,r=i+R[i]>>1,md=l+r>>1;
    24             if(r>=l)a[l]--,a[md+1]++,add(b[l],r),add(b[md+1],1-md-(i&1));
    25         }
    26         for(int i=1;i<=n;++i)d[i]=b[i],add(b[i+1],b[i]+a[i]),a[i+1]+=a[i],a[i]=b[i]=0;
    27         ans=0; for(int i=1;i<n;++i)ans=(ans+1ll*c[i]*d[i+1])%mod; cout<<ans<<endl;
    28     }
    29 }
    View Code

    T3:最有价值

    大意:数字串,选中一个子序列,对于数字$i$若选中了则$b_i$代价,每多选一次额外付出$a_i$。位置$i,j$同时选收益$w_{i,j}$。最大化收益。$n le 100, T le 20$

    同时选有收益,非常经典的网络流模型。

    处理每种数字的贡献,只需要新建$10$个点表示数字,连$a_i-b_i$的边表示选这种数有这样的代价,再有这10个点向序列对应位置连边。

    可以用老方法讲点数优化至$O(n)$但是没啥必要,就这样吧。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 66666
     4 #define inf 998244353
     5 int n,ec=1,t,fir[S],l[S],to[S],v[S],T=6666,w[111][111],a[11],pc,b[11],ans,d[S],q[S];char s[111];
     6 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;}
     7 void con(int a,int b,int w){link(a,b,w);link(b,a,0);}
     8 bool bfs(){
     9     for(int i=1;i<=T;++i)d[to[i]]=0;d[0]=1;
    10     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(!d[to[i]]&&v[i])d[q[++t]=to[i]]=d[q[h]]+1;
    11     return d[T];
    12 }
    13 int dfs(int p,int f){
    14     if(p==T)return f;int r=f;
    15     for(int i=fir[p];i&&r;i=l[i])if(d[to[i]]==d[p]+1&&v[i]){
    16         int x=dfs(to[i],min(v[i],r));
    17         if(!x)d[to[i]]=0;
    18         v[i]-=x;v[i^1]+=x;r-=x;
    19     }return f-r;
    20 }
    21 int main(){
    22 //    freopen("3.in","r",stdin);freopen("3.out","w",stdout);
    23     cin>>t;while(t-->0){
    24         scanf("%d%s",&n,s+1);pc=n+10;
    25         for(int i=0;i<=9;++i)scanf("%d%d",&a[i],&b[i]),con(0,n+i+1,b[i]-a[i]);
    26         for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)scanf("%d",&w[i][j]),ans+=w[i][j];
    27         for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)con(i,++pc,inf),con(j,pc,inf),con(pc,T,w[i][j]+w[j][i]);
    28         for(int i=1;i<=n;++i)con(0,i,a[s[i]-48]),con(n+s[i]-47,i,inf),ans-=w[i][i];
    29         while(bfs())ans-=dfs(0,inf);printf("%d
    ",ans);
    30         for(int i=0;i<=T;++i)fir[i]=0;ec=1;ans=0;
    31     }
    32 }
    View Code
  • 相关阅读:
    CGAffineTransform的使用大概:
    CYLTabBarController的简单使用
    Masonry详解
    Swift学习 (四)
    《Advanced Bash-scripting Guide》学习(二):测试脚本调用的参数是否正确
    《Advanced Bash-scripting Guide》学习(一):对一个增强和广义的删除logfile的脚本的理解
    [JSOI2007]字符加密Cipher
    codevs 3160 最长公共子串
    codevs 1500 后缀排序
    浅谈后缀数组
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12289500.html
Copyright © 2011-2022 走看看