5.27 考试修改+总结

这是一个悲伤的故事

上午写manacher的时候往里面加#号,然后统计有效字符的个数

然后我就开始模拟,一个长度为6的串我都能数错有多少个有效字符

我把2个字符数成了3个!然后暴力就挂掉了5分。。

为什么这几天的暴力总是会挂掉,真是奇怪(看来是最近自己内心不太稳了

(大概是被那个梦吓得吧QAQ)

今天又A了两道题目,感觉天天都是两道正解+挂掉的暴力QAQ

先放题解吧

第一题是之前数位DP坑掉的题目,然后今天尝试着写了写,感觉不是很难

但是并不是用数位DP做的

先考虑加密的情况,我们只需要统计每一位0,1出现的次数就可以了

然后这个随便搞一搞就能搞出来

考虑不加密的情况,不难发现如果从某一位开始不贴上界的话,那么后面都可以通过^变成1

然后分情况讨论这一位上界是0和这一位上界是1就可以了,模拟一下小数据就可以写出来了

写完之后以为题目的1e-5是绝对误差,然后就开始疯狂调精度

最后差不多差距1e-2,然后发现题目说的是相对误差QAQ 浪费了好长时间

得到了一些奇怪的调精度的方法,譬如输出long double的时候强制转成double会损失些精度

我们可以先用long long输出整数位,然后转double输出小数位

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#define eps 1e-8
using namespace std;

typedef long long LL;
LL n;
double k;
long double p;
long double p1,p2;
long double A,B,C;
int Num[72],len=0;
LL f[72][2];
LL suf[72];

void check(LL n){
    memset(Num,0,sizeof(Num));len=0;
    if(!n){Num[++len]=0;return;}
    while(n)Num[++len]=(n&1),n>>=1;
}
bool judge(){
    for(int i=1;i<=len;++i)if(Num[i]==0)return false;
    return true;
}

int main(){
    //freopen("news.in","r",stdin);
    //freopen("news.out","w",stdout);
    scanf("%lld",&n);
    scanf("%lf",&k);p=k;
    n--;check(n);
    if(judge()){
        if(fabs(p-1)<eps){
            long double ans=n;
            LL tmp=(LL)(ans);
            printf("%lld.",tmp);
            ans=ans-tmp;ans*=1e10;
            printf("%010.0lf\n",(double)(ans));
            return 0;
        }else if(fabs(p)<eps){
            long double ans=n;
            ans/=2.0;
            LL tmp=(LL)(ans);
            printf("%lld.",tmp);
            ans=ans-tmp;ans*=1e10;
            printf("%010.0lf\n",(double)(ans));
            return 0;
        }
    }
    n++;
    LL tmp=1;
    for(int i=1;i<len;++i)tmp=tmp+(1LL<<(i-1))*Num[i];
    A=(long double)(tmp);p1=p1+(A/n)*(long double)((1LL<<len)-1);
    C=(long double)(1LL<<(len-1));p1=p1+(C/(long double)(n))*C;C/=(long double)(n);
    for(int i=len-1;i>=1;--i){
        if(Num[i]==1){
            C*=0.5;
            p1=p1+C*(long double)((1LL<<i)-1);
            p1=p1+C*(long double)(1LL<<(i-1));
        }else{
            A=C*0.5;
            p1=p1+A*(long double)(1LL<<(i-1));
        }
    }
    suf[0]=1;
    for(int i=1;i<=len;++i)suf[i]=suf[i-1]+(1LL<<(i-1))*Num[i];
    for(int i=len;i>=1;--i){
        if(Num[i]==1){
            LL tmp=(1LL<<(i-1));
            f[i][0]+=tmp;tmp>>=1;
            for(int j=i-1;j>=1;--j){
                f[j][0]+=tmp;
                f[j][1]+=tmp;
            }
            f[i][1]+=suf[i-1];
        }else f[i][0]+=suf[i-1];
    }
    for(int i=1;i<=len;++i){
        A=(long double)(f[i][0]);A/=(long double)(n);
        B=(long double)(f[i][1]);B/=(long double)(n);
        C=(long double)(1LL<<(i-1));
        p2=p2+A*B*C*2.0;
    }
    p=p1*p+p2*(1.0-p);
    tmp=(LL)(p);
    printf("%lld.",tmp);
    p-=tmp;p*=1e10;
    printf("%010.0lf\n",(double)(p));
    return 0;
}

第二题是BZOJ的原题,久仰大名但是从来没写过

今天一看发现是丝薄题,五分钟就秒掉了

然后写了大概20min左右拍上了,卡了卡常数就没有管

首先我们考虑b是a的祖先,那么b有多少个很容易算,满足条件的c就是a的子树大小-1

之后考虑a是b的祖先,我们先思考一下如果没有k的限制,这样的话类似HAOI2015 T1化一下式子算贡献就可以了

具体是这样的:每个点x作为c对a的答案贡献是(dep[x]-dep[a]-1)

因为dep[a]+1和子树大小都是常数,我们只需要用线段树统计子树dep的和就可以了

考虑k的限制,不难发现实际上是给这个题目加了一维深度,即统计贡献的x在dep的某个区间里,其余的不在这个区间的x的贡献都是k

把线段树换成可持久化线段树就可以了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;

typedef long long LL;
const int maxn=300010;
int n,m,u,v,now,k;
int h[maxn],cnt=0;
struct edge{
    int to,next;
}G[maxn<<1];
int pos[maxn],ed[maxn],tot=0;
int dep[maxn],siz[maxn];
int tmp[maxn];
int rt[maxn],sum=0;
struct Seg_Tree{
    int L,R,v;
    LL S;
}t[11000010];

bool cmp(const int &x,const int &y){
    return dep[x]>dep[y];
}
void add(int x,int y){
    ++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;
}
void read(int &num){
    num=0;char ch=getchar();
    while(ch<‘!‘)ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}
void Get_DFS(int u,int f){
    pos[u]=++tot;siz[u]=1;
    for(int i=h[u];i;i=G[i].next){
        int v=G[i].to;
        if(v==f)continue;
        dep[v]=dep[u]+1;
        Get_DFS(v,u);
        siz[u]+=siz[v];
    }ed[u]=tot;return;
}
void build(int &o,int L,int R){
    o=++sum;
    if(L==R)return;
    int mid=(L+R)>>1;
    build(t[o].L,L,mid);
    build(t[o].R,mid+1,R);
}
void UPD(int &o,int L,int R,int p,int v){
    t[++sum]=t[o];o=sum;
    if(L==R){t[o].v++;t[o].S+=v;return;}
    int mid=(L+R)>>1;
    if(p<=mid)UPD(t[o].L,L,mid,p,v);
    else UPD(t[o].R,mid+1,R,p,v);
    t[o].v=t[t[o].L].v+t[t[o].R].v;
    t[o].S=t[t[o].L].S+t[t[o].R].S;
}
int ask_v(int o,int L,int R,int x,int y){
    if(L>=x&&R<=y)return t[o].v;
    int mid=(L+R)>>1;
    if(y<=mid)return ask_v(t[o].L,L,mid,x,y);
    else if(x>mid)return ask_v(t[o].R,mid+1,R,x,y);
    else return ask_v(t[o].L,L,mid,x,y)+ask_v(t[o].R,mid+1,R,x,y);
}
LL ask_S(int A,int B,int L,int R,int x,int y){
    if(L>=x&&R<=y)return t[A].S-t[B].S;
    int mid=(L+R)>>1;
    if(y<=mid)return ask_S(t[A].L,t[B].L,L,mid,x,y);
    else if(x>mid)return ask_S(t[A].R,t[B].R,mid+1,R,x,y);
    else return ask_S(t[A].L,t[B].L,L,mid,x,y)+ask_S(t[A].R,t[B].R,mid+1,R,x,y);
}

int main(){
    //freopen("laugh.in","r",stdin);
    //freopen("laugh.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<n;++i){
        read(u);read(v);
        add(u,v);add(v,u);
    }dep[1]=1;Get_DFS(1,-1);
    for(int i=1;i<=n;++i)tmp[i]=i;
    sort(tmp+1,tmp+n+1,cmp);now=1;
    build(rt[n+1],1,n);
    for(int i=n;i>=1;--i){
        rt[i]=rt[i+1];
        while(now<=n&&dep[tmp[now]]==i){
            u=tmp[now];
            UPD(rt[i],1,n,pos[u],dep[u]);
            now++;
        }
    }
    while(m--){
        read(u);read(k);
        LL Av,AS,Bv,BS;
        LL t1=siz[u]-1;
        LL t2=min(dep[u]-1,k);
        LL ans=t1*t2;
        now=dep[u]+k+1;
        if(now>n)Av=0;
        else Av=ask_v(rt[now],1,n,pos[u],ed[u]);
        BS=ask_S(rt[dep[u]+1],rt[now],1,n,pos[u],ed[u]);
        Bv=t1-Av;
        ans=ans+Av*k;
        ans=ans+BS;
        ans=ans-Bv*(dep[u]+1);
        printf("%lld\n",ans);
    }
    return 0;
}

第三题考场上犯逗,暴力挂掉了5分QAQ

首先如果存在一个串是回文串,答案是inf

之后我们考虑一个回文子串要满足什么条件可以扩展,显然这个回文子串要有一侧碰到边界

那么对于这个串就会剩下右半部分或者左半部分

我们拿别的串去拼剩下的部分就可以了

考虑用图论模型来描述这个概念,我们对于每一个位置用两个点分别表示剩下左边和剩下右边

用边来表示可拼接的转移

我们新建一个节点源点向每个碰到边界的回文子串的另一个边界点建边

注意空串也是一个回文串,所以也要额外建边

之后我们考虑串与串之间的转移情况,设A表示有回文子串的串,B表示另一个用来拼接的串

分类讨论如下:

1、拼接后都不碰到边界,显然不可在扩展,为了方便统计答案我们向汇点建边

2、拼接后A碰边界,B不碰,A的点向B的对应点建边

3、拼接后A不碰边界,B碰边界,A的点向A中匹配B之后的点建边,表示还可以继续匹配

4、都碰边界,A和B形成了一个回文串,答案为inf

之后我们得到了一个图,对于这个图由于每条边都表示一个可行的转移

即如果这个图有环那么答案为inf

否则从S求最长路即为答案

至于判断是否可拼接用字符串相关的数据结构随便就搞定了

本来想自己写写练练码力,结果写完之后发现一堆边界搞错,下标搞混的问题

这真是一个悲伤的故事

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=200010;
int n,m,h[maxn],cnt,blo;
int bin[20],lgl[maxn];
int len[maxn],Slen[maxn];
int L[maxn],R[maxn];
int sa[maxn],rk[maxn],height[maxn];
int st[20][maxn];
int wa[maxn],wb[maxn],wv[maxn],tmp[maxn];
int s[maxn];

struct edge{
	int to,next,w;
}G[30000010];

void add_edge(int x,int y,int z){
	++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt;
}
void Get_sa(int *r, int n, int m) {
	int *x=wa,*y=wb;
	for(int i=0;i<m;++i)tmp[i]=0;
	for(int i=0;i<n;++i)tmp[x[i]=r[i]]++;
	for(int i=1;i<m;++i)tmp[i]+=tmp[i-1];
	for(int i=n-1;i>=0;--i)sa[--tmp[x[i]]]=i;
	for(int j=1;j<n;j<<=1){
		int p=0;
		for(int i=n-j;i<n;++i)y[p++]=i;
		for(int i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j;
		for(int i=0;i<m;++i)tmp[i]=0;
		for(int i=0;i<n;++i)tmp[wv[i]=x[y[i]]]++;
		for(int i=1;i<m;++i)tmp[i]+=tmp[i-1];
		for(int i=n-1;i>=0;--i)sa[--tmp[wv[i]]]=y[i];
		swap(x,y);
		p=1;x[sa[0]]=0;
		for(int i=1;i<n;++i){
			x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
		}
		if(p>=n)break;
		m=p;
	}
}
void Get_height(int *r,int n){
	int i,j,k;
	for(i=j=k=0;i<n;height[rk[i++]]=k){
		for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
	}return;
}
void Get_ST(int n){
	for(int i=1;i<=n;++i)st[0][i]=height[i];
	for(int i=1;i<=lgl[n];++i){
		for(int j=1;j+bin[i]-1<=n;++j){
			st[i][j]=min(st[i-1][j],st[i-1][j+bin[i-1]]);
		}
	}return;
}
int ST_ask(int x,int y){
	x=rk[x];y=rk[y];
	if(x>y)swap(x,y);x++;
	int k=lgl[y-x+1];
	return min(st[k][x],st[k][y-bin[k]+1]);
}
int ask(int a,int x,int b,int y){
	if(x>0)a=L[a]+x-1;
	else a=R[a]+len[a]+x;
	if(y>0)b=L[b]+y-1;
	else b=R[b]+len[b]+y;
	return ST_ask(a,b);
}
int S,T,TMP;
LL dis[maxn];
int deg[maxn],q[maxn];
bool vis[maxn],in[maxn];

bool check(int u){
	vis[u]=in[u]=true;
	for(int i=h[u];i;i=G[i].next){
		int v=G[i].to;
		deg[v]++;
		if(in[v]||(!vis[v]&&check(v)))return true;
	}return in[u]=0;
}
int Get_id(int x,int y){
	if(x==0)return S;
	if(x==-1)return T;
	if(y==0||y>len[x])return TMP;
	if(y>0)return Slen[x-1]*2+y;
	return Slen[x-1]*2+len[x]-y;
}
void add(int a,int x,int b,int y,int w){
	a=Get_id(a,x);b=Get_id(b,y);
	add_edge(a,b,w);
}

char str[maxn];

int main(){
	bin[0]=1;
	for(int i=1;i<20;++i)bin[i]=bin[i-1]<<1;
	lgl[0]=-1;
	for(int i=1;i<maxn;++i)lgl[i]=lgl[i>>1]+1;
	blo=26;
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%s",str);
		len[i]=strlen(str);
		Slen[i]=Slen[i-1]+len[i];
		s[m++]=++blo;L[i]=m;
		for(int j=0;j<len[i];++j)s[m++]=str[j]-‘a‘+1;
		s[m++]=++blo;R[i]=m;
		for(int j=0;j<len[i];++j)s[m++]=str[len[i]-j-1]-‘a‘+1;
	}
	Get_sa(s,m+1,300);
	for(int i=0;i<=m;++i)rk[sa[i]]=i;
	Get_height(s,m);
	Get_ST(m);
	S=0;T=Slen[n]*2+10;TMP=T+1;
	bool flag=true;
	for(int i=1;i<=n;++i){
		if(ask(i,1,i,-(len[i]+1))==len[i]){
			flag=false;
		}
	}
	LL ans=0;
	for(int i=1;flag&&i<=n;++i){
		for(int j=1;j<=len[i];++j){
			int R=ask(i,j,i,-j),L=min(j,len[i]-j+1);
			ans=max(ans,1LL*R*2-1);
			if(L==R){
				if(j>len[i]-j+1)add(0,0,i,-(j-R),R*2-1);
				else add(0,0,i,j+R,2*R-1);
			}
		}
		for(int j=2;j<=len[i];++j){
			int R=ask(i,j,i,-(j-1)),L=min(j-1,len[i]-j+1);
			ans=max(ans,1LL*R*2);
			if(L==R){
				if(j-1>len[i]-j+1)add(0,0,i,-(j-1-R),R*2);
				else add(0,0,i,j+R,R*2);
			}
		}
		add(0,0,i,1,0);
		add(0,0,i,-len[i],0);
		for(int j=1;j<=len[i];++j){
			int wf=0,wr=0;
			for(int k=1;k<=n;++k){
				int R=ask(i,j,k,-len[k]);
				if(R==len[i]-j+1)add(i,j,k,-(len[k]-R),R*2);
				else if(R==len[k])add(i,j,i,j+R,R*2);
				else wf=max(wf,R*2);
				R=ask(i,-j,k,1);
				if(R==j)add(i,-j,k,R+1,R*2);
				else if(R==len[k])add(i,-j,i,-(j-R),R*2);
				else wr=max(wr,R*2);
			}
			if(wf>0)add(i,j,-1,0,wf);
			if(wr>0)add(i,-j,-1,0,wr);
		}
	}
	if(!flag||check(S)||vis[TMP])ans=-1;
	else{
		int he=0,t=0;
		q[t++]=S;
		while(he!=t){
			int u=q[he++];
			for(int i=h[u];i;i=G[i].next){
				int v=G[i].to;
				dis[v]=max(dis[v],dis[u]+G[i].w);
				ans=max(ans,dis[v]);
				if(!--deg[v])q[t++]=v;
			}
		}
	}
	if(ans==-1)printf("Infinity\n");
	else printf("%lld\n",ans);
	return 0;
}

考试总结:

1、第三题的5分丢的太可惜,如果考试的时候在认真一点就好了

2、看题不仔细导致因为相对误差的事情浪费了大概一个半小时左右

3、最近由于题目比较简单,很容易想出正解

养成了想不出正解就不是很想写题的坏毛病,于是心态不稳,暴力就总是会出问题

从明天开始不管怎么样,都要认真对待每一道题目,哪怕是暴力也要写的优美,争取能拿到最高的分数

还有两个月啦,加油!

(两个月换三个月,貌似很值?

坑掉的东西:字符串专项训练

时间: 2024-12-15 15:45:53

5.27 考试修改+总结的相关文章

5.28 考试修改+总结

今天又是一个悲伤的故事,所有排名比我高的人第一题都A了 而我第一题爆零了 但是开心的事情是:第一题没有说是简单图,所以题解是错的 不管怎么样,将错就错吧 今天下午断网了,所以这时候才写blog 第一题 由于题目中没有给出欧拉图的概念,所以我完全不知道它在说啥,于是就爆零了 然后欧拉图就是存在欧拉回路的简单图,具有以下特点: 1.联通 2.度数都是偶数 显然我们将错就错看题目的话,把欧拉图数目*(n*(n-1)/2+1)就可以得到答案了 然后我们很容易知道度数均为偶数的图的数目是2^((n-1)*

6.15 考试修改+总结

昨天考崩了QAQ 几乎写全了暴力分,然而并没有什么卵用 因为只要A掉一道题就比我分高了,比我分高的也至少A掉了一道题QAQ 感觉到一丝淡淡的忧桑 貌似THUSC最后听讲课的那些人几乎都A了两题 看来我的THUSC果然只是RP好啊 第一题 显然选色数最少的颜色,设颜色数为m 考虑存在某个点的方案数,设这个点到k距离i个点 则方案数为(n-1-i)!/ ((m-i)!*j!*k!……) j,k等是其他颜色的色数 总方案也是非常好算的,这样我们就可以计算每个点对于期望的贡献了 这样做是O(n^2)的

5.26 考试修改+总结

论写5K+的代码在只有样例的条件下都可以调对 由此可见,勇气才是成功的关键 先放题解吧 第一题上午写的暴力不小心忘记题目换根之后还会染色了 然后就挂成了5分QAQ 有很大的部分分是SDOI染色,还有一部分是旅行 但是考试犯懒没有写 很容易发现任何一种颜色在树上都是连续的一段 那么我们不妨这么定义,如果一条边两端颜色不相同,我们定义为虚边,会对子树每个答案产生+1的贡献 如果两端颜色相同,我们定义为实边,不会产生贡献 不难发现,这样定义后的实边和虚边的性质和LCT的定义是一样的 我们考虑使用LCT

9.27考试 SD_le NOIP模拟题 第三题 建造游乐场题解

这道题当时没读完题时脑部了无数种问法,然而最后还是猝不及防.一开始还以为是结论题,然而死也退不出来,就先去打第二题了.然后在想这道题时,我想到的是这样的思路(由于当时时间紧迫,尚未完善): 我每次向图中增加两个点,那么这两个点对于所有入度为偶数的点是否连接一定是一致的,如果这两个点相连,那么如果使他们分别和一个入度为单数的点相连,那么他们就是新的入度为单数的点,其他情况就不叙述了,太多了.还不是正解. 由于最后时间太紧迫了,我不得不打暴力去保分,结果还好丢人好丢人的打错了-- 正解其实还是挺有意

3.27考试小记

一天考了两场-- 上来先看第一题,发现题目中有一个LIS,然而我并不知道它是何物,看了一会没看出来LIS是啥就先放着了,第二题读完发现是原题,而且还不是特别费码力那种,开心.第三题读完发现还是原题,难道这场是信心赛? 于是先打最好打的第三题,打完之后发现图建对了,边权建错了,有点小慌,想了一会没想出来,就先放着了,然后去打第二题,按照之前的打法打完了调了一会就过了,本来想对拍一下保险一点,然而并不会造数据,好尴尬--于是接着做第三题,又推了一会推出来了边权,样例都过了,这次也会造数据,然而并不会

6.3 考试修改+总结

今天下午考试被FFT和数论题目翔了一脸QAQ 做的是Newscafe杯的题目 第一题 异化多肽 显然构造多项式f 答案是f+f^2+f^3…… 化简一下得1/(1-f) 之后多项式求逆即可 考试的时候推了好久的多项式求逆的式子(感觉自己什么都忘光了 #include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<algorithm> #define

6.11 考试修改+总结

第三题至今没敢写,感觉好恐怖QAQ 今天考得好糟糕 第一题只写了10分的暴力+(k=1)20分的网络流 后来题解告诉我k>1的时候可以分治到k=1,每层分治解决方法是同k=1的 考试的时候没有注意到2^k这个比较神奇的可以分治的性质 而且自己考场上丝薄了,没有发现因为是二分图可以直接跑欧拉回路的性质,而是裸套网络流模型 第二题其实已经接近想出了题解 自己考试的时候成功证明了暴力的复杂度是线性的 但是没有想到如何寻找0-1对,然后就只能暴力用Splay维护1所在的位置了 默默祈祷数据不要太卡我的做

6.10 考试修改+总结+颓废记

昨天晚上得到了非常不爽的消息,zcg要去给高一讲课,而我并不能去 虽然什么事情并不能都顺着我的心意来吧,但是这件事情真是让人越想越不痛快 要知道,我从去年就一直期待着给高一讲课呢 所以今天考试非常不开心,一般这个时候我会选择爆零的 但是想了想觉得爆零太难看,就看了看好像第一题可做 在教学楼里颓废了好久然后吃了点东西,用最后的时间码完了第一题 (反正二.三题我没看出来怎么做,所以暴力也不想写了 然后惊讶的是,只有第一题程序的窝rank1了QAQ 先放题解吧 第一题: 首先我们注意到转置的实质是某个

6.19 考试修改+总结

QAQ 又是一套水题集合 然后忧伤的故事是老师把时间调到了四个小时半 我又因为想要出道题花了半个小时写了一些其他的东西 然后最后没有写完题!QAQ 不然第三题可能多拿点分 上午的时候把所有题目的正解都想了出来 唯一美中不足的是自己想的第三题是O(n^4*300)的是时间复杂度 实际上离散化区间之后只会有n个区间,时间复杂度就是O(n^5)了QAQ 先说题解把 第一题 决战圆锥曲线 显然给定你的那个函数a*x+b*y+c*x*y对于x,y是相对等价的 又因为题目的输入具有随机性,显然可以通过维护线