考前的几场比赛都打得比较稳定,感觉人品被用光了。突然对NOIP比较害怕。感觉会出现一些莫名其妙的错误。
然后就立了个flag。
去巴蜀看了考场,今年的键盘比较舒服,座位不是去年的塑料凳子了,好评。
进了考场打了各种图论和数论板子,最后和PWJ大佬打了个最小表示法。我还记得大佬一开始还没有打对。最后还玩了金山打字通,总的来说感觉心情不是很紧张。
这一天活活把AK丢啦。
很早就来到了巴蜀,但是比较疲倦,非常想要睡觉。然后考试时非常受影响。
看到T1就很爽了:这不是O(1)结论题吗?输出 ab−a−b 注意一个long long就好了。一分钟100分到手。
T2一看就是暴力恶心模拟,由于个人觉得代码能力有点弱,先看的T3。
T3看数据范围:K<=50!瞬间想出正解:最短路+记忆化搜索!但是突然看到可能有无穷多的方案,虽然只有三组数据,但是心里有点慌。先敲了最短路部分和记忆化搜索计数部分,而且第一次没有敲对,心态有点崩:T3这么简单,不会是想错了吧?反正时间还很充裕,先敲T2。
然后T2敲了1h(最后还是错的),头脑已经很不清醒了。还好T3想出了正解:只有边权全是0的环才可能造成无穷解的情况:因为在零环上跑多少圈,都不会增加dis值。否则已经会增加dis值,只会有有限解。求零环,可以新建一个只有零权边的图,Tarjan判环即可。
无穷解的条件:
敲完过了大样例,心情很愉快。还剩20min左右,然而当时今本上难以思考了,竟然没有检查出T2的错误。
下午睡了个觉,突然发现T2有个地方处理得有问题,最坏情况下只有30分,心态有些凄凉,但是并没有崩。
D1这么简单,D2岂不是……
期望得分230~300。
这一天爆炸了。
T1一看,就是判断一个连通性,并查集 O(n2) 即可水过。看到数据范围略大,几乎全用了double。
T2数据范围这么小,不是状压就是搜。但是感觉上更像一个状压DP。然而一开始对状态一点想法都没有。上了两趟厕所才有思路。然而考后发现定的是一个错误的状态,但心想问题不大,至少过40分,更何况这么小的数据一般都能骗很高的分。
T3一看就是一道数据结构题,但是并没有想到怎么做。主要是因为没有写过动态开点,根本没往这方面想。看到空间范围心态爆炸,敲了个50分骗分(而且20分的骗分忘开long long GG)。
最后民间数据测的时候发现T1写错了一个细节,心态爆炸。
期望得分……不敢想了。
出成绩的时候爽死了:虽然分数并不是很高,但是骗到了很多分。最后得分100+90+100+60+80+30=460。
还是有些遗憾,毕竟D2T1这么水的题都没有A掉。今年省选压力可能会比较大,接下来的东西非常多,要好好努力才行。
最后附上两天T3的AC代码:
D1T3 最短路+Tarjan+记忆化搜索:
#include
#include
#include
#include
#include
#define ll long long
#define MAXN 100005
#define MAXM 200005
using namespace std;
int N,M,K;
ll P,f[MAXN][55];
bool INF;
int en[MAXM],las[MAXN],nex[MAXM],len[MAXM],tot;
void Add(int x,int y,int z)
{
en[++tot]=y;
nex[tot]=las[x];
las[x]=tot;
len[tot]=z;
}
int EN[MAXM],LAS[MAXN],NEX[MAXM],LEN[MAXM],TOT;
void ADD(int x,int y,int z)
{
EN[++TOT]=y;
NEX[TOT]=LAS[x];
LAS[x]=TOT;
LEN[TOT]=z;
}
int zen[MAXM],zlas[MAXN],znex[MAXM],ztot;
void Zadd(int x,int y)
{
zen[++ztot]=y;
znex[ztot]=zlas[x];
zlas[x]=ztot;
}
queue<int>Q;
int dis[MAXN];
bool mark[MAXN];
void SPFA(int s)
{
int i,y,x;
for(i=1;i<=N;i++)dis[i]=1e9;
Q.push(s);dis[s]=0;
while(Q.size())
{
x=Q.front();Q.pop();mark[x]=false;
for(i=LAS[x];i;i=NEX[i])
{
y=EN[i];
if(dis[y]>dis[x]+LEN[i])
{
dis[y]=dis[x]+LEN[i];
if(!mark[y])mark[y]=true,Q.push(y);
}
}
}
}
queue<int>_Q;
int _dis[MAXN];
bool _mark[MAXN];
void _SPFA(int s)
{
int i,y,x;
for(i=1;i<=N;i++)_dis[i]=1e9;
_Q.push(s);_dis[s]=0;
while(_Q.size())
{
x=_Q.front();_Q.pop();_mark[x]=false;
for(i=las[x];i;i=nex[i])
{
y=en[i];
if(_dis[y]>_dis[x]+len[i])
{
_dis[y]=_dis[x]+len[i];
if(!_mark[y])_mark[y]=true,_Q.push(y);
}
}
}
}
ll GetAns(int x,int k)
{
if(~f[x][k])return f[x][k];
if(x==N)
{
if(k==0)return 1;
//return 0;
}
int i,j,y,t;
ll Ans=0;
for(i=las[x];i;i=nex[i])
{
y=en[i];t=len[i]-(dis[x]-dis[y]);
if(t>=0&&t<=k)Ans=(Ans+GetAns(y,k-t))%P;
}
return f[x][k]=Ans;
}
stack<int>S;
bool In[MAXN];
int VT,dfn[MAXN],low[MAXN];
void Tarjan(int x)
{
low[x]=dfn[x]=++VT;
In[x]=true;
S.push(x);
int i,y,cnt=0;
bool tmp=false;
for(i=zlas[x];i;i=znex[i])
{
y=zen[i];
if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
else if(In[y])low[x]=min(low[x],dfn[y]);
}
if(dfn[x]!=low[x])return;
do
{
cnt++;
y=S.top();S.pop();In[y]=false;
if(dis[y]+_dis[y]<=dis[1]+K)tmp=true;
}while(x!=y);
if(cnt>1&&tmp)INF=true;
}
void Clear()
{
memset(las,0,sizeof(las));
memset(LAS,0,sizeof(LAS));
memset(zlas,0,sizeof(zlas));
memset(f,-1,sizeof(f));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
tot=TOT=ztot=0;INF=false;
}
int main()
{
int T,i,x,y,z;
ll Ans;
scanf("%d",&T);
while(T--)
{
Clear();Ans=0;
scanf("%d%d%d%lld",&N,&M,&K,&P);
for(i=1;i<=M;i++)
{
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z);ADD(y,x,z);
if(z==0)Zadd(x,y);
}
_SPFA(1);
SPFA(N);
for(i=1;i<=N;i++)if(!dfn[i])Tarjan(i);
if(INF)
{
puts("-1");continue;
}
for(i=0;i<=K;i++)Ans=(Ans+GetAns(1,i))%P;
printf("%lld\n",Ans);
}
}
D2T3 动态开点线段树
#include
#include
#define MAXN 1000005
#define MAXM 1000005
#define MAXT 12000005
#define ll long long
using namespace std;
int N,M,Q;
vector G[MAXN];
ll tot,rt[MAXN],ls[MAXT],rs[MAXT],sum[MAXT];
void Update(int p)
{
sum[p]=sum[ls[p]]+sum[rs[p]];
}
int Ins(int l,int r)
{
sum[++tot]=r-l+1;
return tot;
}
int GetAns(int p,int l,int r,int k)
{
if(l==r)return l;
int mid=l+r>>1,ans;
if(!ls[p])ls[p]=Ins(l,mid);
if(!rs[p])rs[p]=Ins(mid+1,r);
if(sum[ls[p]]>=k)ans=GetAns(ls[p],l,mid,k);
else ans=GetAns(rs[p],mid+1,r,k-sum[ls[p]]);
return ans;
}
void Sub(int p,int l,int r,int k)
{
if(l==r){sum[p]--;return;}
int mid=l+r>>1;
if(k<=mid)Sub(ls[p],l,mid,k);
else Sub(rs[p],mid+1,r,k);
Update(p);
}
int main()
{
ll Ans,x,y,id;
int T;
scanf("%d%d%d",&N,&M,&Q);
T=Q;
rt[0]=Ins(1,N+Q);
for(int i=1; i<=N; i++)rt[i]=Ins(1,M+Q);
while(T--)
{
scanf("%lld%lld",&x,&y);
if(y1,M+Q,y);
if(id<=M-1)Ans=1ll*(x-1)*M+id;
else Ans=G[x][id-M];
Sub(rt[x],1,M+Q,id);
printf("%lld\n",Ans);
G[0].push_back(Ans);
id=GetAns(rt[0],1,N+Q,x);
if(id<=N)Ans=1ll*id*M;
else Ans=G[0][id-N-1];
G[x].push_back(Ans);
Sub(rt[0],1,N+Q,id);
}
else
{
id=GetAns(rt[0],1,N+Q,x);
if(id<=N)Ans=1ll*id*M;
else Ans=G[0][id-N-1];
printf("%lld\n",Ans);
Sub(rt[0],1,N+Q,id);
G[0].push_back(Ans);
}
}
}