高一下四月日记

4.1

闲话

  • 早上让集体散跑三圈后再去吃饭。
  • 上午得知远足时间调整到了周五,且返校时间不变,仍为周日晚上。
  • 晚上到机房后 \(miaomiao\) 说以后我们上奥赛课直接去 \(504\) 就行了。

做题纪要

luogu P1175 表达式的转换

  • 开两个栈辅助建后缀表达式。

    点击查看代码
    char s[110];
    deque<char>s1,s2;
    deque<int>s3;
    int val(char x)
    {
        if(x=='(') return 0;
        if(x=='+'||x=='-')  return 1;
        if(x=='*'||x=='/')  return 2;
        if(x=='^')  return 3;
        return -1;
    } 
    void work(char c)
    {
        int a=s3.back();  s3.pop_back();
        int b=s3.back();  s3.pop_back();
        if(c=='+')  s3.push_back(b+a);
        if(c=='-')  s3.push_back(b-a);
        if(c=='*')  s3.push_back(b*a);
        if(c=='/')  s3.push_back(b/a);
        if(c=='^')  s3.push_back(pow(b,a));
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
        freopen("in.in","r",stdin);
        freopen("out.out","w",stdout);
    #endif
        int n,i;
        char c;
        cin>>(s+1);  n=strlen(s+1);
        for(i=1;i<=n;i++)
        {
            if('0'<=s[i]&&s[i]<='9')  s1.push_back(s[i]);
            else  if(s[i]=='(')  s2.push_back(s[i]);
            else  if(s[i]==')')
            {
                while(s2.back()!='(')
                {
                    s1.push_back(s2.back());
                    s2.pop_back();
                }
                s2.pop_back();
            }
            else
            {
                if(s2.empty()==0)
                {
                    while(s2.empty()==0&&val(s2.back())>=val(s[i])&&(s2.back()!='^'||s[i]!='^'))
                    {
                        s1.push_back(s2.back());
                        s2.pop_back();
                    }
                }
                s2.push_back(s[i]);
            }
        }
        while(s2.empty()==0)
        {
            s1.push_back(s2.back());
            s2.pop_back();
        }
        for(i=0;i<s1.size();i++)  cout<<s1[i]<<" ";
        cout<<endl;
        while(s1.empty()==0)
        {
            c=s1.front();  s1.pop_front();
            if('0'<=c&&c<='9')  s3.push_back(c-'0');
            else  
            {
                work(c);
                for(i=0;i<s3.size();i++)  cout<<s3[i]<<" ";
                for(i=0;i<s1.size();i++)  cout<<s1[i]<<" ";
                cout<<endl;
            }
        }
        return 0;
    }
    

P898. 交通网络

4.2

闲话

  • 上午年级又通知远足改到了明天。
  • 地理课上老师说把课本都讲一遍是不可能的了,只能做前几年的学考真题然后对着题讲知识点了。

4.3

闲话

  • 远足后放假。

4.4

闲话

  • 作业怎么这么多啊。

4.5

闲话

  • 起床时感觉有点头晕,以为只是睡眠时间不够导致的。
  • 下午返校的过程中,发现头稍微有点烫,到宿舍后量了下体温发现达到了 \(38.2°C\) ,到机房喝了包布洛芬后达到了 \(38.8°C\) ,但仍很清醒。
  • 吃完晚饭回来后就直接在机房睡觉了。

4.6

闲话

  • 早上没去吃饭,因仍发烧故在机房又睡了约一上午。

做题纪要

P1007. 小 F 的疑惑

luogu P8123 [BalticOI 2021] Inside information (Day1)

  • 操作 \(3\) 看起来非常棘手。

  • 手摸后发现正序加边时 \(a \in S_{x}\) 对应倒序加边时 \(x \in S_{a}\) ,以时间为下标维护即可。

  • 合并的过程需要可持久化。

    点击查看代码
    int x[240010],y[240010],ans[240010];
    char op[240010];
    struct SMT
    {
    	int root[120010],rt_sum;
    	struct SegmentTree
    	{
    		int ls,rs,siz;
    	}tree[240010<<6];
    	#define lson(rt) (tree[rt].ls)
    	#define rson(rt) (tree[rt].rs)
    	void clear()
    	{
    		rt_sum=0;
    		memset(root,0,sizeof(root));
    	}
    	int build_rt()
    	{
    		rt_sum++;  int rt=rt_sum;
    		lson(rt)=rson(rt)=tree[rt].siz=0;
    		return rt;
    	}
    	void pushup(int rt)
    	{
    		tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz;
    	}
    	void update(int pre,int &rt,int l,int r,int pos)
    	{
    		rt=build_rt();
    		tree[rt]=tree[pre];  tree[rt].siz++;
    		if(l==r)  return;
    		int mid=(l+r)/2;
    		if(pos<=mid)  update(lson(pre),lson(rt),l,mid,pos);
    		else  update(rson(pre),rson(rt),mid+1,r,pos);
    	}
    	int merge(int rt1,int rt2,int l,int r)
    	{
    		if(rt1==0||rt2==0)  return rt1+rt2;
    		int rt=build_rt();
    		if(l==r)
    		{
    			tree[rt].siz=tree[rt1].siz+tree[rt2].siz;
    			return rt;
    		}
    		int mid=(l+r)/2;
    		lson(rt)=merge(lson(rt1),lson(rt2),l,mid);
    		rson(rt)=merge(rson(rt1),rson(rt2),mid+1,r);
    		pushup(rt);
    		return rt;
    	}
    	int query1(int rt,int l,int r,int pos)
    	{
    		if(rt==0)  return 0;
    		if(l==r)  return 1;
    		int mid=(l+r)/2;
    		if(pos<=mid)  return query1(lson(rt),l,mid,pos);
    		else  return query1(rson(rt),mid+1,r,pos);
    	}
    	int query2(int rt,int l,int r,int x,int y)
    	{
    		if(rt==0)  return 0;
    		if(x<=l&&r<=y)  return tree[rt].siz;
    		int mid=(l+r)/2,ans=0;
    		if(x<=mid)  ans+=query2(lson(rt),l,mid,x,y);
    		if(y>mid)  ans+=query2(rson(rt),mid+1,r,x,y);
    		return ans;
    	}
    }T;	
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)  T.update(T.root[0],T.root[i],1,n,i);
    	for(i=1;i<=n+m-1;i++)
    	{
    		cin>>op[i]>>x[i];
    		if(op[i]!='C')  cin>>y[i];
    		if(op[i]=='S')  T.root[x[i]]=T.root[y[i]]=T.merge(T.root[x[i]],T.root[y[i]],1,n);
    		if(op[i]=='Q')  ans[i]=T.query1(T.root[x[i]],1,n,y[i]);
    	}
    	T.clear();
    	for(i=n+m-1;i>=1;i--)
    	{
    		if(op[i]=='S')
    		{
    			T.update(T.root[x[i]],T.root[x[i]],1,n+m-1,i);
    			T.root[x[i]]=T.root[y[i]]=T.merge(T.root[x[i]],T.root[y[i]],1,n+m-1);
    		}
    	}
    	for(i=1;i<=n+m-1;i++)
    	{
    		if(op[i]=='Q')  cout<<(ans[i]==1?"yes":"no")<<endl;
    		if(op[i]=='C')  cout<<T.query2(T.root[x[i]],1,n+m-1,1,i)+1<<endl;
    	}
    	return 0;
    }
    

4.8

闲话

做题纪要

CF1342F Make It Ascending

luogu P5789 [TJOI2017] 可乐(数据加强版)

  • 多倍经验: luogu P3758 [TJOI2017] 可乐

  • 将总和也放到转移矩阵里即可。

    点击查看代码
    const int p=2017;
    int n;
    struct Matrix
    {
    	int ma[110][110];
    	Matrix()
    	{
    		memset(ma,0,sizeof(ma));
    	}
    	Matrix operator * (const Matrix &another) const
    	{
    		Matrix ans;
    		for(int i=1;i<=n+1;i++)
    		{ 
    			for(int j=1;j<=n+1;j++)
    			{
    				for(int h=1;h<=n+1;h++)
    				{
    					ans.ma[i][j]=(ans.ma[i][j]+ma[i][h]*another.ma[h][j]%p)%p;
    				}
    			}
    		}
    		return ans;
    	}
    }f,base;
    Matrix qpow(Matrix a,int b)
    {
    	Matrix ans;
    	for(int i=1;i<=n+1;i++)  ans.ma[i][i]=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a;
    		b>>=1;
    		a=a*a;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int m,t,u,v,i;
    	cin>>n>>m;  f.ma[1][1]=1;
    	for(i=1;i<=m;i++)
    	{
    		cin>>u>>v;
    		base.ma[u][v]=base.ma[v][u]=1;
    	}
    	for(i=1;i<=n+1;i++)  base.ma[i][i]=base.ma[i][n+1]=1;
    	cin>>t; 
    	f=f*qpow(base,t+1);
    	cout<<f.ma[1][n+1]<<endl;
    	return 0;
    }
    

4.9

闲话

  • 晚上发了通用技术学考复习资料,班主任说到下周考前不会给我们上课时间,让我们自己找时间复习。

4.10

闲话

  • 到机房后又被 \(feifei\) 赶到 \(510\) 了。
  • 晚新闻班长开会回来说这周末要刮十二级大风,所有同学禁止离校。

做题纪要

luogu P2619 [国家集训队] Tree I

  • WQS 二分

    • WQS 二分常用于解决形如选择恰好 \(k\) 次,询问最大/小价值的问题。
    • \(f_{i}\) 表示选择 \(i\) 次时的最优答案,使用前提是 \((i,f_{i})\) 构成了一个凸包(上、下凸包均可),即斜率单调递增/单调递减。
    • 考虑二分,每次二分一个 \(mid\) 表示选一次的附加权值,当最优方案选的物品次数 \(>k\) 则减小 \(mid\) 否则增加 \(mid\) (以上凸包为例),最后答案去掉 \(mid\) 的影响。
    • 其实质是每次二分一个斜率 \(k\)\(y=kx+b\) 去切这个上凸包,每次最先切到的点就是最优答案,然后通过调整斜率 \(k\) 来达到切到某一位置的目的。
    • 一些需要注意的事项
      • 因为斜率每次切到的都是一定范围内的点。故最后的答案应该去掉的是最优方案实际选的次数乘附加权值的贡献。
      • 假设最终斜率为 \(mid\) 时最大点 \(<k\) ,斜率为 \(mid+1\) 时最大点 \(>k\) 。此时似乎需要写实数二分才能正确求解答案,但这并不是完全必要的。我们可以在排序上做些手脚(每个属性都定义偏序关系),使选的次数 \(\ge k\) 时进行更新答案(具体 \(\ge,\le\) 因题和写法而异)。
      • 始终清楚自己二分对物品造成的影响是增多还是减少。
  • 本题中由 \(Kruskal\) 相关理论和删/加边的单调性可知是一个下凸包。

    点击查看代码
    struct node
    {
    	int u,v,w,c;
    	bool operator < (const node another) const
    	{
    		return (w==another.w)?(c<another.c):(w<another.w);
    	}
    }e[100010];
    int u[100010],v[100010],c[100010],w[100010];
    struct DSU
    {
    	int fa[50010];
    	void init(int n)
    	{
    		for(int i=1;i<=n;i++)  fa[i]=i;
    	}
    	int find(int x)
    	{
    		return fa[x]==x?x:fa[x]=find(fa[x]);
    	} 
    }D;
    pair<int,int> check(int n,int m,int mid)
    {
    	D.init(n);
    	int sum=0,ans=0;
    	for(int i=1;i<=m;i++)  e[i]=(node){u[i],v[i],w[i]-(1-c[i])*mid,c[i]};
    	sort(e+1,e+1+m);
    	for(int i=1;i<=m;i++)
    	{
    		int x=D.find(e[i].u),y=D.find(e[i].v);
    		if(x!=y)
    		{
    			D.fa[x]=y;
    			ans+=e[i].w;
    			sum+=(1-e[i].c);
    		}
    	}
    	return make_pair(ans,sum);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,k,l=-100,r=100,ans=0,mid,i;
    	cin>>n>>m>>k;
    	for(i=1;i<=m;i++)
    	{
    		cin>>u[i]>>v[i]>>w[i]>>c[i];
    		u[i]++;  v[i]++;
    	}
    	while(l<=r)
    	{
    		mid=(l+r)>>1;
    		if(check(n,m,mid).second>=k)// 选择的数量多了,减多点
    		{
    			ans=mid;
    			r=mid-1;
    		}
    		else  l=mid+1;
    	}
    	cout<<check(n,m,ans).first+k*ans<<endl;
    	return 0;
    }
    

4.11

闲话

  • 政治两节课几乎把必修一讲完了,计划明天上午前两节课到滏阳楼因上周远足少了的两节体育课。
  • 信息课上老师说她也有过一段时间的奥赛教练经历(看来初三原班主任说的就是她和其他一些人了),然后喂了一堆鸡汤。
  • 晚新闻班长说轰轰烈烈的双休改革应该已经结束了,下周开始集体跑早操,后面就逐渐恢复到和原来一样了;班主任说明天正常在班里进行周测,原计划补的政治课待定。

4.12

闲话

  • 周测了近半天,直到第十节才开始上奥赛课。

做题纪要

luogu P5633 最小度限制生成树

CF125E MST Company

luogu P4983 忘情

4.13

闲话

  • 上午 \(7:30 \sim 11:00\) 被拉去打 【MX-J8】梦熊 CSP-J 2024 模拟赛(同步赛) 了。结束后 \(huge\)\(NOI\) 前部分分都是非常重要的,现在打模拟赛就要开始养成不能不打部分分的习惯;针对空间限制的问题,省选前应该都是使用 Arbiter 测评,以静态内存为计算,但今年 @5k_sync_closer “以身试法”得出省选按照实际使用内存来计算,以后怎么样还说不定呢,让我们现在就开始重视内存问题;然后单独讲了下 \(Linux\) 终端下如何使用 size 测试内存。
  • 下午第九、十节课回去补生物周测。
  • 晚上去看心理剧。原远足总结部分因时间问题取消了,后面的十大学星评选仅让有同学参加的班级进行投票了。

做题纪要

luogu P11213 【MX-J8-T1】 竹竿

  • 令最大值和次大值分局两侧即可。

    点击查看代码
    int a[100010],b[100010];
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("bamboo.in","r",stdin);
    	freopen("bamboo.out","w",stdout);
    #endif
    	int n,mx=0,se=0,i;
    	cin>>n;
    	for(i=1;i<=n;i++)  
    	{
    		cin>>a[i]>>b[i];
    		if(max(b[i],a[i]-b[i])>mx)
    		{
    			se=max(mx,min(b[i],a[i]-b[i]));
    			mx=max(b[i],a[i]-b[i]);
    		}
    		else  se=max(se,max(b[i],a[i]-b[i]));
    	}
    	cout<<mx+se<<endl;
    	return 0;
    }
    

luogu P11214 【MX-J8-T2】 黑洞

  • 不妨每个 \(k\) 独立考虑,每一维的贡献就只有 \(\times 0/1/2\)

  • 求出贡献范围后分段考虑即可。

    点击查看代码
    const ll p=1000000007;
    ll a[200010],s[200010];
    vector<ll>d;
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("hole.in","r",stdin);
    	freopen("hole.out","w",stdout);
    #endif
    	ll n,ans=1,mul,l=0x3f3f3f3f,r=0x3f3f3f3f,inv=qpow(2,p-2,p),i;
    	cin>>n;  mul=qpow(2,n,p);
    	for(i=1;i<=n;i++)  cin>>s[i];
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		l=min(l,min(a[i]-1,s[i]-a[i]));
    		r=min(r,max(a[i]-1,s[i]-a[i]));
    	}
    	ans=(ans+l*mul%p)%p;  d.push_back(r);
    	for(i=1;i<=n;i++)
    	{
    		if(l<=min(a[i]-1,s[i]-a[i])&&min(a[i]-1,s[i]-a[i])<=r)  
    			d.push_back(min(a[i]-1,s[i]-a[i]));
    	}
    	sort(d.begin(),d.end());
    	for(i=0;i+1<d.size();i++)
    	{
    		mul=mul*inv%p;
    		ans=(ans+(d[i+1]-d[i])*mul%p)%p;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

luogu P11215 【MX-J8-T3】水星湖

  • 记录每个位置最早被种下树的时间然后每次都进行 \(BFS\) 更新的时间复杂度为 \(O(rnm)\) ,且关于时间的处理细节较多,写法有点屎。

  • 考虑使用优先队列代替上面所说的每次都进行 \(BFS\) ,时间复杂度为 \(O(nm \log nm)\)

  • 具体实现时,可以将死亡看做在 \(0.5\) 秒处的操作,统一 \(\times 2\) 省去浮点数。

    点击查看代码
    const int dx[4]={1,0,-1,0},dy[4]={0,-1,0,1};
    struct node
    {
    	ll t;
    	int x,y,op;
    	bool operator < (const node &another) const
    	{
    		return t>another.t;
    	}
    }tmp;
    priority_queue<node>q;
    int vis[3010][3010],c[3010][3010],ins[3010][3010],a[100010][3],b[100010][3],n,m;	
    bool check(int x,int y)
    {
    	if(c[x][y]==1)  return true;
    	for(int i=0;i<=3;i++)
    	{
    		int nx=x+dx[i],ny=y+dy[i];
    		if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&(vis[nx][ny]==1||ins[nx][ny]==1))  return true;
    	}
    	return false;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("lake.in","r",stdin);
    	freopen("lake.out","w",stdout);
    #endif 
    	int op,r,x,y,nx,ny,ans=0,i,j;
    	ll k,t;
    	cin>>n>>m>>op>>r>>k;  k*=2;
    	for(i=1;i<=op;i++)
    	{
    		cin>>a[i][1]>>b[i][1]>>a[i][2]>>b[i][2];
    		for(j=a[i][1];j<=a[i][2];j++)  c[j][b[i][1]-1]=c[j][b[i][2]+1]=1;
    		for(j=b[i][1];j<=b[i][2];j++)  c[a[i][1]-1][j]=c[a[i][2]+1][j]=1;
    		for(x=a[i][1];x<=a[i][2];x++)  for(y=b[i][1];y<=b[i][2];y++)  vis[x][y]=1;
    	}
    	for(i=1;i<=n;i++)  for(j=1;j<=m;j++)  if(vis[i][j]==1)  c[i][j]=0;
    	for(j=1;j<=r;j++)
    	{
    		cin>>t>>x>>y;  t*=2;
    		q.push((node){t,x,y,0});
    	}
    	while(q.empty()==0)
    	{
    		t=q.top().t;  x=q.top().x;  y=q.top().y;  op=q.top().op;  q.pop();
    		if(op==0)
    		{
    			if(ins[x][y]==0)
    			{
    				ins[x][y]=1;
    				if(check(x,y)==false)  q.push((node){t+k+1,x,y,1});
    				for(i=0;i<=3;i++)
    				{
    					nx=x+dx[i],ny=y+dy[i];
    					if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&ins[nx][ny]==0&&c[nx][ny]==1)    q.push((node){t+2,nx,ny,0});
    				}
    			}
    		}
    		else  if(check(x,y)==false)  ins[x][y]=0;
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)  ans+=(ins[i][j]==1);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

luogu P6246 [IOI 2000] 邮局 加强版 加强版

CF1279F New Year and Handle Change

  • 不妨将大/小写分开做,分别计算大/小写字符的最小值后然后取 \(\min\) ,本质是在取若干个区间令其贡献为 \(0\)

  • 使用 WQS 二分求解。

    点击查看代码
    const ll inf=1000000000000;
    ll a[1000010],b[1000010],f[1000010],g[1000010];
    char s[1000010];
    bool check(ll n,ll m,ll len,ll mid)
    {
    	for(ll i=1;i<=n;i++)
    	{
    		f[i]=f[i-1]+a[i];  g[i]=g[i-1];
    		if(f[max(i-len,0ll)]-mid<f[i])
    		{
    			f[i]=f[max(i-len,0ll)]-mid;
    			g[i]=g[max(i-len,0ll)]+1;
    		}
    		else  if(f[max(i-len,0ll)]-mid==f[i])  g[i]=max(g[i],g[max(i-len,0ll)]+1);
    	}
    	return g[n]>=m;
    }
    ll solve(ll n,ll m,ll len,ll op)
    {
    	ll l=-inf,r=inf,ans=0,mid;
    	for(ll i=1;i<=n;i++)  a[i]=('a'<=s[i]&&s[i]<='z')^op;
    	while(l<=r)
    	{
    		mid=(l+r)/2;
    		if(check(n,m,len,mid)==true)
    		{
    			ans=mid;
    			r=mid-1;
    		}
    		else  l=mid+1;
    	}
    	check(n,m,len,ans);
    	return f[n]+ans*m;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,m,len;
    	cin>>n>>m>>len;  scanf("%s",s+1);
    	cout<<min(solve(n,m,len,0),solve(n,m,len,1))<<endl;
    	return 0;
    }
    

luogu P5308 [COCI 2018/2019 #4] Akvizna

  • 斜率优化辅助 WQS 二分,需要实数域上二分来保证精度。

    点击查看代码
    const double eps=1e-12;
    double f[100010];
    ll g[100010];
    deque<ll>q;
    ll x(ll i)
    {
    	return i;
    }
    double y(ll i)
    {
    	return f[i];
    }
    double slope(ll u,ll v)
    {
    	return 1.0*(y(v)-y(u))/(x(v)-x(u));
    }
    bool check(ll n,ll m,double mid)
    {
    	q.clear();  q.push_back(0);
    	for(ll i=1;i<=n;i++)
    	{
    		while(q.size()>=2&&slope(q.front(),q[1])>1.0/i+eps)  q.pop_front();
    		f[i]=f[q.front()]+1.0*(i-q.front())/i-mid;
    		g[i]=g[q.front()]+1;
    		while(q.size()>=2&&slope(q[q.size()-2],q.back())+eps<slope(q.back(),i))  q.pop_back();
    		q.push_back(i);
    	}
    	return g[n]>=m;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,m;
    	double l=-1000000,r=1000000,ans=0,mid;
    	cin>>n>>m;
    	while(r-l>eps)
    	{
    		mid=(l+r)/2;
    		if(check(n,m,mid)==true)
    		{
    			ans=mid;
    			l=mid;
    		}
    		else r=mid;  
    	}
    	check(n,m,ans);
    	printf("%.9lf\n",f[n]+ans*m);
    	return 0;
    }
    

4.14

闲话

  • 早操德育主任声称经他检验合格的班级才能去吃饭,有点形式主义了。
  • 历史课上老师说因期中考试冲击了课程安排,所以预计在下周结课。讲到了世界古代史。
  • 得知通用技术学考各班是自己班主任监考。
  • 晚三前半截改成了化学,和明天上午第一节换了一下。中途从教室前面的扬声器上突然出现了一只蝙蝠,在教室飞了约 \(7 \min\) 才走,并留下了它吃剩下的虫子尸体在窗台上作为遗产。

4.15

闲话

  • 通用技术的学考由上午第 \(5\) 节课提前到了大课间。进场后右边是 @jijidawang 。题目和之前发的复习资料基本没有原题,以 \(60 \%\) 正确率算通过的话,应该能过吧?

做题纪要

luogu B4312 [语言月赛 202504] 炸鸡奶茶

  • 顺序结构。

    点击查看代码
    ll f,m,n;
    cin>>f>>m>>n;
    cout<<(n/7)*(2*f+m)<<endl;
    

luogu B4313 [语言月赛 202504] 洛谷月赛

  • 分支结构。

    点击查看代码
    int l,e;
    cin>>l>>e;
    if((l>=6&&e==1)||(l>=8))  cout<<3<<endl;
    else  if(l>=3)  cout<<6<<endl;
    else  cout<<"Impossible"<<endl;
    

luogu B4314 [语言月赛 202504] 魔方回收

  • 循环结构。

    点击查看代码
    int n,a=0,b=0,c=0,x,y,z,i;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>x>>y>>z;
        a+=8-x;  b+=12-y;  c+=1-z;
    }
    cout<<min({a/8,b/12,c})<<endl;
    

luogu B4315 [语言月赛 202504] 地铁停靠

  • 循环结构。

    点击查看代码
    int t[60],s[60];
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,x,y,ans=0,i;
    	cin>>n;
    	for(i=1;i<=n-1;i++)  cin>>t[i];
    	for(i=1;i<=n;i++)  cin>>s[i];
    	cin>>x>>y;
    	for(i=x;i<=y;i++)  ans+=s[i];
    	for(i=x;i<=y-1;i++)  ans+=t[i];
    	cout<<ans<<endl;
    	return 0;
    }
    

luogu B4316 [语言月赛 202504] 整除判断

  • 循环结构。

    点击查看代码
    int dight(int n)
    {
    	int ans=0;
    	while(n)
    	{
    		ans+=n%10;
    		n/=10;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int m,n,x,flag=0,i;
    	cin>>m>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>x;
    		if(x%m!=0&&dight(x)%m==0)
    		{
    			flag=1;
    			cout<<x<<endl;
    		}
    	}
    	if(flag==0)  cout<<"None"<<endl;
    	return 0;
    }
    

luogu B4317 [语言月赛 202504] 金币收集

  • 循环结构。

    点击查看代码
    ll a[100010],t[1010],p[1010][1010],cnt[1010];
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,s,m,ans=0,i,j;
    	cin>>n>>s>>m;  s--;
    	for(i=1;i<=m;i++)  cin>>a[i];
    	for(i=0;i<=n-1;i++)
    	{
    		cin>>t[i];
    		for(j=1;j<=t[i];j++)  cin>>p[i][j];
    	}
    	cnt[s]++;
    	if(cnt[s]<=t[s])  ans+=p[s][cnt[s]];
    	for(i=1;i<=m;i++)
    	{
    		if(a[i]==1)  s=(s+1)%n;
    		else  s=(s-1+n)%n;
    		cnt[s]++;
    		if(cnt[s]<=t[s])  ans+=p[s][cnt[s]];
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

luogu B4318 [语言月赛 202504] 古诗求和

  • 循环结构。

    点击查看代码
    char s[510];
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,sum=0,cnt=0,tmp=0,i;
    	cin>>(s+1);  n=strlen(s+1);
    	for(i=1;i<=n;i++)
    	{
    		if(s[i]=='.'||s[i]=='?'||s[i]=='!')
    		{
    			cout<<cnt<<" "<<((sum%2==0)?"Even":"Odd")<<endl;
    			sum=cnt=tmp=0;
    		}
    		else  if('0'<=s[i]&&s[i]<='9')
    		{
    			tmp=tmp*10+s[i]-'0';
    			if(!('0'<=s[i+1]&&s[i+1]<='9'))
    			{
    				sum+=tmp;  cnt++;
    				tmp=0;
    			}
    		}
    	}
    	return 0;
    }
    

luogu B4319 [语言月赛 202504] 礼堂预约

  • 模拟。

    点击查看代码
    const int limit[15]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int vis[4010][20][40][4];
    string s,ans[5010];
    int val(char x,int pd)
    {
    	if((pd==1&&x=='O')||(pd==2&&x=='M'))  return 1;
    	if((pd==1&&x=='C')||(pd==2&&x=='A'))  return 2;
    	return 3;
    }
    struct date
    {
    	int year,month,day;
    	bool operator < (const date &another) const
    	{
    		if(year!=another.year)  return year<another.year;
    		if(month!=another.month)  return month<another.month;
    		return day<another.day;
    	}
    	bool operator != (const date &another) const
    	{
    		return (year!=another.year)||(month!=another.month)||(day!=another.day);
    	}
    }tim;
    int is_leap_year(int x)
    {
    	return (x%100==0)?(x%400==0):(x%4==0);
    }
    date work(int year,int month,int day)
    {
    	day++;
    	if(day>limit[month]+(is_leap_year(year)&&month==2))
    	{
    		month++;  day=1;
    	}
    	if(month>12)
    	{
    		year++;  month=1;
    	}
    	return (date){year,month,day};
    }
    date input(string s)
    {
    	int year=(s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+s[3]-'0';
    	int month=(s[4]-'0')*10+s[5]-'0';
    	int day=(s[6]-'0')*10+s[7]-'0';
    	return (date){year,month,day};
    }
    string print(int year,int month,int day)
    {
    	string s=to_string(year);
    	if(month<10)  s+='0';
    	s+=to_string(month);
    	if(day<10)  s+='0';
    	s+=to_string(day);
    	return s;
    }
    struct activity
    {
    	int type,peroid,id;
    	date tim;
    	bool operator < (const activity &another) const
    	{
    		if(type!=another.type)  return another.type<type;
    		if(tim!=another.tim)  return another.tim<tim;
    		if(peroid!=another.peroid)  return another.peroid<peroid;
    		return another.id<id;
    	}
    }tmp;
    priority_queue<activity>q;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,type,peroid,id,year,month,day,i;
    	char c1,c2;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>c1>>s>>c2;
    		q.push((activity){val(c1,1),val(c2,2),i,input(s)});
    	}
    	while(q.empty()==0)
    	{
    		tmp=q.top();  q.pop();
    		type=tmp.type;  peroid=tmp.peroid;  id=tmp.id;  tim=tmp.tim;
    		year=tim.year;  month=tim.month;  day=tim.day;
    		if(vis[year][month][day][peroid]==0)
    		{
    			vis[year][month][day][peroid]=1;
    			ans[id]=print(year,month,day);
    		}
    		else  q.push((activity){type,peroid,id,work(year,month,day)});
    	}
    	for(i=1;i<=n;i++)   cout<<ans[i]<<endl;
    	return 0;
    }
    

CF321E Ciel and Gondolas

4.16

闲话

  • 语文老师出差了,临走前生称我们会遇到各种各样的老师来代课。
  • 生物老师说等五一后气温才逐渐稳定,那时候年级才会给开空调。
  • 地理老师说去年学考难度较大,几位老师间对答案也存在争议, \(206,207\) 能拿到 \(90pts\) 就已经很好了,我们拿到 \(70pts\) 还够呛。
  • 因历史进度有点满,所以晚三前半截改成了历史课,最终讲到了英法美三国资产阶级革命。
  • 班主任说等气温逐渐稳定后年级才会给开空调。但宿舍里已经能开了。

4.17

闲话

  • \(504\) 关网了,遂又到 \(510\) 了。

做题纪要

P269. 赤(red)

CF1799F Halve or Subtract

  • 二维 WQS 二分

    点击查看代码
    const ll inf=1000000000000;
    ll a[5010],n,b,k1,k2;
    ll f(ll x)
    {
    	return (x+1)/2;
    }
    ll g(ll x)
    {
    	return max(x-b,0ll);
    }
    ll f_2d(ll x,ll y) 
    {
    	ll ans=y*k2;
    	for(ll i=1;i<=n;i++)  ans+=min({a[i],f(a[i])-x,g(a[i])-y,min(f(g(a[i])),g(f(a[i])))-x-y});
    	return ans;
    }
    ll wqs_2d(ll x)
    {
    	ll l=-inf,r=inf,mid,c1,c2;
    	while(r-l>0)
    	{
    		mid=(l+r)>>1;
    		c1=f_2d(x,mid);  c2=f_2d(x,mid+1);
    		if(c1==c2)  return c1;
    		else  if(c1<c2)  l=mid+1;
    		else  r=mid;
    	}
    	return f_2d(x,l);
    }
    ll f_1d(ll x)
    {
    	return wqs_2d(x)+x*k1;
    }
    ll wqs_1d()
    {
    	ll l=-inf,r=inf,mid,c1,c2;
    	while(r-l>0)
    	{
    		mid=(l+r)>>1;
    		c1=f_1d(mid);  c2=f_1d(mid+1);
    		if(c1==c2)  return c1;
    		else  if(c1<c2)  l=mid+1;
    		else  r=mid;
    	}
    	return f_1d(l);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif  
    	ll t,i;
    	cin>>t;
    	for(;t>=1;t--)
    	{
    		cin>>n>>b>>k1>>k2;
    		for(i=1;i<=n;i++)  cin>>a[i];
    		cout<<wqs_1d()<<endl;
    	}
    	return 0;
    }
    

luogu P3354 [IOI 2005] Riv 河流

  • \(f_{x,y}\) 表示以 \(x\) 为根的子树内在 \(y\) 处建立伐木场(不一定要运到 \(y\) )的最小运费,枚举祖先转移即可。

    点击查看代码
    const ll inf=1000000000000;
    struct node
    {
    	ll nxt,to,w;
    }e[110];
    ll head[110],a[110],dep[110],f[110][110],g[110][110],s[110],top=0,cnt=0;
    void add(ll u,ll v,ll w)
    {
    	cnt++;  e[cnt]=(node){head[u],v,w};  head[u]=cnt;
    }
    void dfs(ll x)
    {
    	for(ll i=head[x];i!=0;i=e[i].nxt)
    	{
    		dep[e[i].to]=dep[x]+e[i].w;
    		dfs(e[i].to);
    	}
    }
    void dp(ll x,ll mid)
    {
    	top++;  s[top]=x;
    	for(ll i=head[x];i!=0;i=e[i].nxt)
    	{
    		dp(e[i].to,mid);
    		for(ll j=1;j<=top;j++)
    		{
    			f[x][s[j]]+=f[e[i].to][s[j]];  g[x][s[j]]+=g[e[i].to][s[j]];
    		}
    	}
    	f[x][x]-=mid;  g[x][x]++;
    	for(ll i=1;i<=top;i++)
    	{
    		f[x][s[i]]+=a[x]*(dep[x]-dep[s[i]]);
    		if(f[x][s[i]]>=f[x][x])
    		{
    			f[x][s[i]]=f[x][x];  g[x][s[i]]=g[x][x];
    		}
    	}
    	top--;
    }
    bool check(ll mid,ll k)
    {
    	top=0;
    	memset(f,0,sizeof(f));  memset(g,0,sizeof(g));
    	dp(1,mid);
    	return g[1][1]>=k;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,k,u,w,l=-inf,r=inf,mid,ans=0,i;
    	cin>>n>>k;  n++;  k++;
    	for(i=2;i<=n;i++)
    	{
    		cin>>a[i]>>u>>w;  u++;
    		add(u,i,w);
    	}
    	dfs(1);
    	while(l<=r)
    	{
    		mid=(l+r)/2;
    		if(check(mid,k)==true)
    		{
    			ans=mid;
    			r=mid-1;
    		}
    		else  l=mid+1;
    	}
    	check(ans,k);
    	cout<<f[1][1]+ans*k<<endl;
    	return 0;
    }
    

4.18

闲话

  • 政治课讲完了必修二和必修三的前一半。
  • 下午大课间的时候外面零零星星地开始下雨。
  • 晚上 \(18:15\) 放假,因昨天下午我忘开窗了所以被留下打扫教室。收拾完行李准备出校的时候雨已经下得很大了。
  • 回到家后发现 \(miaomiao\) 没把我家长拉到省集的群里,遂不能去省集了。

4.19

闲话

  • \(15:30\) 在教室坐好,其他学生作为观众开完德育年会后 \(18:00\) 直接离校,奥赛生则即不开会也不离校。
  • 下午 \(miaomiao\) 过来说这周 @ccxswl@CuFeO4 都请假了,就剩我一个了,让我现在多写题,把题量赶上来,然后问我现在在写啥题,我说在补 3.动态规划 ,然后又问去年暑假讲的知识点都吸收了吗,我说就剩容斥等数学的东西没学了。
  • 晚上 \(miaomiao\) 对其他人说现在还没到大规模打模拟赛的时候,即使有模拟赛也是凑着调考顺便考一下,所以出现的一些挂分、思维能力不够是正常现象;课程里多了很多知识点,但基本都是省选后的,他们不用学,在暑假前学完树剖、分块、莫队、线段树合并、线段树分裂基本就可以了,其他应付 \(NOIP\) 的知识点等暑假再学;现在做题就要开始培养独立思考的能力,比如有人想着想着就去看题解了,说自己会了但实际上只是会了把思路如何去实现的过程,但忽略了如何想到这个思路,之前有一届尝试过在做题的时候关外网,但转头又想到不能因此阻止了想往后学知识的人去往后学知识,这和学 \(whk\) 遇到难题的时候啥都不想,只等着老师去讲是一个道理;现在周末集训就只剩一天了,集体组织听课也不太可能了,刷知识点就使劲往前赶就行了;要善于发现自己身上的长处,你看以前学长讲课的时候都是让擅长某一领域的学长来讲这一领域,还比如前几届也有 \(NOIP\) 完就退役但最后还裸分上清北的,有的人就是比较适应学 \(whk\) ;在机房要管得住自己,\(miaomiao\) 之所以把 @gzxworld 赶走就是因为他管不住自己,本来之前暑假集训的时候 \(miaomiao\) 抓着他打游戏后说了他几句后起码还管点用,但上次又抓着他用图形化搞抛物线来着,所以就把他赶走了。

做题纪要

CF868F Yet Another Minimization Problem

luogu P5574 [CmdOI2019] 任务分配问题

  • 大胆猜测具有代价函数具有决策单调性。

  • 后续做法同 CF868F Yet Another Minimization Problem

    点击查看代码
    ll a[25010],f[30][25010],n,m,l=1,r=0,sum=0;
    struct BIT
    {
    	ll c[2][25010];
    	ll lowbit(ll x)
    	{
    		return (x&(-x));
    	}
    	void add(ll x,ll val)
    	{
    		for(ll i=x;i<=n;i+=lowbit(i))  c[0][i]+=val;
    		for(ll i=x;i>=1;i-=lowbit(i))  c[1][i]+=val;
    	}
    	ll getsum(ll x,ll op)
    	{
    		ll ans=0;
    		if(op==0)  for(ll i=x;i>=1;i-=lowbit(i))  ans+=c[0][i];
    		else  for(ll i=x;i<=n;i+=lowbit(i))  ans+=c[1][i];
    		return ans;
    	}
    }T;
    void add(ll x,ll op)
    {
    	sum+=T.getsum(a[x],op);
    	T.add(a[x],1);
    }
    void del(ll x,ll op)
    {
    	T.add(a[x],-1);
    	sum-=T.getsum(a[x],op);
    }
    ll w(ll x,ll y)
    {
    	while(l>x)
    	{
    		l--;  add(l,1);
    	}
    	while(r<y)
    	{
    		r++;  add(r,0);
    	}
    	while(l<x)
    	{
    		del(l,1);  l++;
    	}
    	while(r>y)
    	{
    		del(r,0);  r--;
    	}
    	return sum;
    }
    void solve(ll l,ll r,ll x,ll y,ll dep)
    {
    	if(l>r)  return;
    	ll mid=(l+r)/2,opt=0,tmp;
    	for(ll i=max(x,1ll);i<=min(y,mid);i++)
    	{
    		tmp=f[dep-1][i-1]+w(i,mid);
    		if(tmp<f[dep][mid])
    		{
    			f[dep][mid]=tmp;  opt=i;
    		}
    	}
    	solve(l,mid-1,x,opt,dep);  solve(mid+1,r,opt,y,dep);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	cin>>n>>m;  memset(f,0x3f,sizeof(f));
    	for(ll i=1;i<=n;i++)  cin>>a[i];
    	f[0][0]=0;
    	for(ll i=1;i<=m;i++)  solve(1,n,1,n,i);
    	cout<<f[m][n]<<endl;
    	return 0;
    }
    

[ABC305Ex] Shojin

4.20

闲话

  • 早上睡过头了,直接拿了点零食在机房楼道里应付做早饭了,然后就被 \(huge\) 发现了。
  • 上午 \(field\) 说等吃完晚饭再回班,晚一、二的语数英学科文化节让在班里补作业,晚三去开学生大会;然后放四边形不等式优化的视频。
  • 因放假前生物老师说今天还有自习,遂下午大课间的时候准备回班看看,刚到电梯楼下就遇见了回班后发现让吃完晚饭再回班的 @wkh2008@CuFeO4@HANGRY_sol
  • 吃完晚饭回班后发现学科文化节改成了公自,然后除物理、语文老师轮番进班告诉我们需要写什么作业。晚二下课后去开期中动员大会,因学科文化节结束得较早,所以提前进行了班级目标的宣誓环节,但我们班没赶上,然后喂了一堆鸡汤。比较重要的是早上吃饭时间调整到了 \(7:15\) ,遂减少了候操的动员时间,但吃完早饭后的时间改成了早预备;晚上吃饭时间调整到了 \(18:15\)

做题纪要

luogu P4383 [八省联考 2018] 林克卡特树

luogu P10981 任务安排 4.2【暂无数据】

  • 多倍经验: luogu P10980 任务安排 4.1【暂无数据】

  • CDQ 分治优化 DP 。

    点击查看代码
    ll f[300010],t[300010],c[300010],k[300010],p[300010],tmp[300010],n,s;
    deque<ll>q;
    bool cmpk(ll a,ll b)
    {
    	return k[a]<k[b];
    }
    ll x(ll i)
    {
    	return c[i];
    }
    ll y(ll i)
    {
    	return f[i];
    }
    bool cmpx(ll a,ll b)
    {
    	return (x(a)==x(b))?(y(a)<y(b)):(x(a)<x(b));
    }
    void cdq(ll l,ll r)
    {
    	if(l==r)  return;
    	ll mid=(l+r)/2;
    	for(ll i=l,x=l,y=mid+1;i<=r;i++)
    	{
    		if(p[i]<=mid)
    		{
    			tmp[x]=p[i];  x++;
    		}
    		else
    		{
    			tmp[y]=p[i];  y++;
    		}
    	}
    	for(ll i=l;i<=r;i++)  p[i]=tmp[i];
    	cdq(l,mid);
    	q.clear();
    	for(ll i=l;i<=mid;i++)
    	{
    		while(q.size()>=2&&(y(q.back())-y(q[q.size()-2]))*(x(p[i])-x(q.back()))>=
    							(y(p[i])-y(q.back()))*(x(q.back())-x(q[q.size()-2])))
    			q.pop_back();
    		q.push_back(p[i]);
    	}
    	for(ll i=mid+1;i<=r;i++)
    	{
    		while(q.size()>=2&&(y(q[1])-y(q.front()))<=k[p[i]]*(x(q[1])-x(q.front())))
    			q.pop_front();
    		f[p[i]]=min(f[p[i]],f[q.front()]+t[p[i]]*(c[p[i]]-c[q.front()])+s*(c[n]-c[q.front()]));
    	}
    	cdq(mid+1,r);
    	sort(p+l,p+r+1,cmpx);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	cin>>n>>s;
    	for(ll i=1;i<=n;i++)
    	{
    		cin>>t[i]>>c[i];  p[i]=i;
    		t[i]+=t[i-1];  c[i]+=c[i-1];  k[i]=t[i]+s;
    	}
    	for(ll i=1;i<=n;i++)  f[i]=t[i]*c[i]+s*c[n];
    	sort(p+1,p+1+n,cmpk);  cdq(1,n);
    	cout<<f[n]<<endl;
    	return 0;
    }
    

luogu P11716 [清华集训 2014] 卡常数

  • 解码通过二分函数求最值来处理。

  • 打延迟删除的标记即可。因为保证数据随机,所以可以不用担心 \(KD-Tree\) 的形态。

    点击查看代码
    const double inf=1e10,eps=1e-8;
    struct node
    {
    	int id;
    	double pos[3];
    }a[140010];
    int it[140010],cur;
    double _a,_b,r;
    double f(double x)
    {
    	return _a*x-_b*sin(x);
    }
    double read(double l,double r,double val)
    {
    	if(val==0)  val=0.1;
    	double mid,x;
    	scanf("%lf",&x);
    	while(r-l>=eps)
    	{
    		mid=(l+r)/2;
    		if(f(val*mid+1)<x)  l=mid;
    		else  r=mid;
    	}
    	return (l+r)/2;
    }
    bool cmp(node x,node y)
    {
    	return x.pos[cur]<y.pos[cur];
    }
    double get_dis(int x,int y)
    {
    	double ans=0;
    	for(int i=0;i<=2;i++)  ans+=(a[x].pos[i]-a[y].pos[i])*(a[x].pos[i]-a[y].pos[i]);
    	return sqrt(ans);
    }
    struct KDT
    {
    	int root;
    	struct kd_tree
    	{
    		int ls,rs,fa,id,flag;
    		double pos[3],mx[3],mn[3];
    	}tree[140010];
    	#define lson(rt) (tree[rt].ls)
    	#define rson(rt) (tree[rt].rs)
    	#define fa(rt) (tree[rt].fa)
    	int build_rt(int id)
    	{
    		int rt=id;
    		lson(rt)=rson(rt)=fa(rt)=tree[rt].flag=0;
    		tree[rt].id=a[id].id;  it[a[id].id]=rt;
    		for(int i=0;i<=2;i++)
    			tree[rt].pos[i]=tree[rt].mx[i]=tree[rt].mn[i]=a[id].pos[i];
    		return rt;
    	}
    	void pushup(int rt)
    	{
    		for(int i=0;i<=2;i++)
    		{
    			if(tree[rt].flag==1)
    			{
    				tree[rt].mx[i]=-inf;  tree[rt].mn[i]=inf;
    			}
    			else  tree[rt].mx[i]=tree[rt].mn[i]=tree[rt].pos[i];
    			if(lson(rt)!=0)
    			{
    				tree[rt].mx[i]=max(tree[rt].mx[i],tree[lson(rt)].mx[i]);
    				tree[rt].mn[i]=min(tree[rt].mn[i],tree[lson(rt)].mn[i]);
    			}
    			if(rson(rt)!=0)
    			{
    				tree[rt].mx[i]=max(tree[rt].mx[i],tree[rson(rt)].mx[i]);
    				tree[rt].mn[i]=min(tree[rt].mn[i],tree[rson(rt)].mn[i]);
    			}
    		}
    	}
    	void build(int &rt,int l,int r,int dir)
    	{
    		int mid=(l+r)/2;  cur=dir;
    		nth_element(a+l,a+mid,a+r+1,cmp);  rt=build_rt(mid);
    		if(l<=mid-1)
    		{
    			build(lson(rt),l,mid-1,(dir+1)%3);
    			fa(lson(rt))=rt;
    		}
    		if(mid+1<=r)
    		{
    			build(rson(rt),mid+1,r,(dir+1)%3);
    			fa(rson(rt))=rt;
    		}
    		pushup(rt);
    	}
    	void insert(int &rt,int id,int dir)
    	{
    		if(rt==0)
    		{
    			rt=build_rt(id);
    			return;
    		}
    		if(a[id].pos[dir]<tree[rt].pos[dir])
    		{
    			insert(lson(rt),id,(dir+1)%3);
    			fa(lson(rt))=rt;
    		}
    		else
    		{
    			insert(rson(rt),id,(dir+1)%3);
    			fa(rson(rt))=rt;
    		}
    		pushup(rt);
    	}
    	void del(int rt)
    	{
    		tree[rt].flag=1;
    		for(;rt!=0;rt=fa(rt))  pushup(rt);
    	}
    	double cost1(int rt,int pos)
    	{
    		double ans=0;
    		for(int i=0;i<=2;i++)
    		{
    			if(a[pos].pos[i]<tree[rt].mn[i])  ans+=(tree[rt].mn[i]-a[pos].pos[i])*(tree[rt].mn[i]-a[pos].pos[i]);
    			if(a[pos].pos[i]>tree[rt].mx[i])  ans+=(tree[rt].mx[i]-a[pos].pos[i])*(tree[rt].mx[i]-a[pos].pos[i]);
    		}
    		return sqrt(ans);
    	}
    	double cost2(int rt,int pos)
    	{
    		double ans=0;
    		for(int i=0;i<=2;i++)  ans+=max((tree[rt].mx[i]-a[pos].pos[i])*(tree[rt].mx[i]-a[pos].pos[i]),
    										(tree[rt].mn[i]-a[pos].pos[i])*(tree[rt].mn[i]-a[pos].pos[i]));
    		return sqrt(ans);
    	}
    	int query(int rt,int pos)
    	{
    		if(rt==0||cost1(rt,pos)-r>eps||r-cost2(rt,pos)>eps)  return -1;
    		if(tree[rt].flag==0&&abs(r-get_dis(rt,pos))<eps)  return tree[rt].id;
    		int ans=query(lson(rt),pos);
    		if(ans==-1)  return query(rson(rt),pos);
    		else  return ans;
    	}
    }K;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,_n,m,pd,p,ans=0,i,j;
    	scanf("%d%d%lf%lf",&n,&m,&_a,&_b);  _n=n;
    	for(i=1;i<=n;i++)
    	{
    		for(j=0;j<=2;j++)  scanf("%lf",&a[i].pos[j]);
    		a[i].id=i;
    	}
    	K.build(K.root,1,n,0);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d",&pd);
    		if(pd==0)
    		{
    			n++;  p=round(read(1,_n,ans));
    			for(j=0;j<=2;j++)  a[n].pos[j]=read(-100,100,ans);
    			K.del(it[p]);  a[n].id=p;  K.insert(K.root,n,0);
    		}
    		else
    		{
    			for(j=0;j<=2;j++)  a[0].pos[j]=read(-100,100,ans);
    			r=read(0,400,ans);
    			printf("%d\n",ans=K.query(K.root,0));
    		}
    	}
    	return 0;
    }
    

luogu P5471 [NOI2019] 弹跳

  • 朴素 \(KD-Tree\) 优化建图需要 \(O(m\sqrt{n})\) 的空间,视实现方式可以获得 \(76 \sim 88pts\) 不等。这里 因为偷懒所以使用了 vector ,仅获得了 \(76pts\)

    • \(KD-Tree\) 优化建图
      • 基本思路同线段树优化建图,每个点代表一个矩形。\(KD-Tree\) 上父子间进行连边,点连区间同理进行区间定位操作。

      • 为方便代码书写,可以将 \(KD-Tree\) 上点的编号统一进行移位。

        点击查看代码
        struct node
        {
        	int pos[2],id;
        }a[70010];
        int vis[140010],dis[140010],l[2],r[2],n,cur;
        vector<pair<int,int> >e[140010];
        bool cmp(node x,node y)
        {
        	return x.pos[cur]<y.pos[cur];
        }
        void add(int u,int v,int w)
        {
        	e[u].push_back(make_pair(v,w));
        }
        struct KDT_Q_MG
        {
        	int root;
        	struct node
        	{
        		int ls,rs,id,pos[2],mx[2],mn[2];
        	}tree[70010];
        	#define lson(rt) (tree[rt].ls)
        	#define rson(rt) (tree[rt].rs)
        	int build_rt(int id)
        	{
        		int rt=id;
        		lson(rt)=rson(rt)=0;
        		tree[rt].id=a[id].id;
        		for(int i=0;i<=1;i++)
        			tree[rt].pos[i]=tree[rt].mx[i]=tree[rt].mn[i]=a[id].pos[i];
        		return rt;
        	}
        	void pushup(int rt)
        	{
        		for(int i=0;i<=1;i++)
        		{
        			tree[rt].mx[i]=tree[rt].mn[i]=tree[rt].pos[i];
        			if(lson(rt)!=0)
        			{
        				tree[rt].mx[i]=max(tree[rt].mx[i],tree[lson(rt)].mx[i]);
        				tree[rt].mn[i]=min(tree[rt].mn[i],tree[lson(rt)].mn[i]);
        			}
        			if(rson(rt)!=0)
        			{
        				tree[rt].mx[i]=max(tree[rt].mx[i],tree[rson(rt)].mx[i]);
        				tree[rt].mn[i]=min(tree[rt].mn[i],tree[rson(rt)].mn[i]);
        			}
        		}
        	}
        	void build(int &rt,int l,int r,int dir)
        	{
        		int mid=(l+r)/2;  cur=dir;
        		nth_element(a+l,a+mid,a+r+1,cmp);  rt=build_rt(mid);
        		add(tree[mid].id+n,tree[mid].id,0);
        		if(l<=mid-1)
        		{
        			build(lson(rt),l,mid-1,dir^1);
        			add(tree[rt].id+n,tree[lson(rt)].id+n,0);
        		}
        		if(mid+1<=r)
        		{
        			build(rson(rt),mid+1,r,dir^1);
        			add(tree[rt].id+n,tree[rson(rt)].id+n,0);
        		}
        		pushup(rt);
        	}
        	void update(int rt,int l[2],int r[2],int u,int w)
        	{
        		if(rt==0)  return;
        		for(int i=0;i<=1;i++)  if(l[i]>tree[rt].mx[i]||r[i]<tree[rt].mn[i])  return;
        		int flag=1;
        		for(int i=0;i<=1;i++)  flag&=(l[i]<=tree[rt].mn[i]&&tree[rt].mx[i]<=r[i]);
        		if(flag==1)  
        		{
        			add(u,tree[rt].id+n,w);
        			return;
        		}
        		flag=1;
        		for(int i=0;i<=1;i++)  flag&=(l[i]<=tree[rt].pos[i]&&tree[rt].pos[i]<=r[i]);
        		if(flag==1)  add(u,tree[rt].id,w);
        		update(lson(rt),l,r,u,w);  update(rson(rt),l,r,u,w);
        	}
        }K;
        void dijkstra(int s)
        {
        	memset(vis,0,sizeof(vis));  memset(dis,0x3f,sizeof(dis));
        	priority_queue<pair<int,int> >q;
        	dis[s]=0;  q.push(make_pair(-dis[s],s));
        	while(q.empty()==0)
        	{
        		int x=q.top().second;  q.pop();
        		if(vis[x]==0)
        		{
        			vis[x]=1;
        			for(int i=0;i<e[x].size();i++)
        			{
        				if(dis[e[x][i].first]>dis[x]+e[x][i].second)
        				{
        					dis[e[x][i].first]=dis[x]+e[x][i].second;
        					q.push(make_pair(-dis[e[x][i].first],e[x][i].first));
        				}
        			}
        		}
        	}
        }
        int main()
        {
        // #define Isaac
        #ifdef Isaac
        	freopen("in.in","r",stdin);
        	freopen("out.out","w",stdout);
        #endif
        	int m,w,h,u,i;
        	cin>>n>>m>>w>>h;
        	for(i=1;i<=n;i++)
        	{
        		cin>>a[i].pos[0]>>a[i].pos[1];
        		a[i].id=i;
        	}
        	K.build(K.root,1,n,0);
        	for(i=1;i<=m;i++)
        	{
        		cin>>u>>w>>l[0]>>r[0]>>l[1]>>r[1];
        		K.update(K.root,l,r,u,w);
        	}
        	dijkstra(1);
        	for(i=2;i<=n;i++)  cout<<dis[i]<<endl;
        	return 0;
        }
        
  • 为节省空间,手动实现上述连边过程即可。

    点击查看代码
    struct node
    {
    	int pos[2],id;
    }a[70010];
    struct edge
    {
    	int nxt,w,id;
    }e[150010];
    int head[70010],vis[140010],dis[140010],it[70010],l[150010][2],r[150010][2],n,cur,cnt=0;
    priority_queue<pair<int,int> >q;
    bool cmp(node x,node y)
    {
    	return x.pos[cur]<y.pos[cur];
    }
    void add(int u,int w,int id)
    {
    	cnt++;  e[cnt]=(edge){head[u],w,id};  head[u]=cnt;
    }
    struct KDT_Q_MG
    {
    	int root;
    	struct kd_tree
    	{
    		int ls,rs,id,pos[2],mx[2],mn[2];
    	}tree[70010];
    	#define lson(rt) (tree[rt].ls)
    	#define rson(rt) (tree[rt].rs)
    	int build_rt(int id)
    	{
    		int rt=id;
    		lson(rt)=rson(rt)=0;
    		tree[rt].id=a[id].id;  it[a[id].id]=rt;
    		for(int i=0;i<=1;i++)
    			tree[rt].pos[i]=tree[rt].mx[i]=tree[rt].mn[i]=a[id].pos[i];
    		return rt;
    	}
    	void pushup(int rt)
    	{
    		for(int i=0;i<=1;i++)
    		{
    			tree[rt].mx[i]=tree[rt].mn[i]=tree[rt].pos[i];
    			if(lson(rt)!=0)
    			{
    				tree[rt].mx[i]=max(tree[rt].mx[i],tree[lson(rt)].mx[i]);
    				tree[rt].mn[i]=min(tree[rt].mn[i],tree[lson(rt)].mn[i]);
    			}
    			if(rson(rt)!=0)
    			{
    				tree[rt].mx[i]=max(tree[rt].mx[i],tree[rson(rt)].mx[i]);
    				tree[rt].mn[i]=min(tree[rt].mn[i],tree[rson(rt)].mn[i]);
    			}
    		}
    	}
    	void build(int &rt,int l,int r,int dir)
    	{
    		int mid=(l+r)/2;  cur=dir;
    		nth_element(a+l,a+mid,a+r+1,cmp);  rt=build_rt(mid);
    		if(l<=mid-1)  build(lson(rt),l,mid-1,dir^1);
    		if(mid+1<=r)  build(rson(rt),mid+1,r,dir^1);
    		pushup(rt);
    	}
    	void update(int rt,int l[2],int r[2],int w)
    	{
    		if(rt==0)  return;
    		for(int i=0;i<=1;i++)  if(l[i]>tree[rt].mx[i]||r[i]<tree[rt].mn[i])  return;
    		int flag=1;
    		for(int i=0;i<=1;i++)  flag&=(l[i]<=tree[rt].mn[i]&&tree[rt].mx[i]<=r[i]);
    		if(flag==1)  
    		{
    			relax(tree[rt].id+n,w);
    			return;
    		}
    		flag=1;
    		for(int i=0;i<=1;i++)  flag&=(l[i]<=tree[rt].pos[i]&&tree[rt].pos[i]<=r[i]);
    		if(flag==1)  relax(tree[rt].id,w);
    		update(lson(rt),l,r,w);  update(rson(rt),l,r,w);
    	}
    	void relax(int x,int w)
    	{
    		if(dis[x]>w)
    		{
    			dis[x]=w;
    			q.push(make_pair(-dis[x],x));
    		}
    	}
    	void dijkstra(int s)				
    	{
    		memset(vis,0,sizeof(vis));  memset(dis,0x3f,sizeof(dis));
    		dis[s]=0;  q.push(make_pair(-dis[s],s));
    		while(q.empty()==0)
    		{
    			int x=q.top().second;  q.pop();
    			if(vis[x]==0)
    			{
    				vis[x]=1;
    				if(x<=n)  for(int i=head[x];i!=0;i=e[i].nxt)
    					update(root,l[e[i].id],r[e[i].id],dis[x]+e[i].w);
    				else
    				{
    					relax(x-n,dis[x]);  int rt=it[x-n];
    					if(lson(rt)!=0)  relax(tree[lson(rt)].id+n,dis[x]);
    					if(rson(rt)!=0)  relax(tree[rson(rt)].id+n,dis[x]);
    				}
    			}
    		}
    	}
    }K;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int m,w,h,u,i;
    	scanf("%d%d%d%d",&n,&m,&w,&h);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].pos[0],&a[i].pos[1]);  a[i].id=i;
    	}
    	K.build(K.root,1,n,0);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d%d%d",&u,&w,&l[i][0],&r[i][0],&l[i][1],&r[i][1]);
    		add(u,w,i);
    	}
    	K.dijkstra(1);
    	for(i=2;i<=n;i++)  printf("%d\n",dis[i]);
    	return 0;
    }
    

4.21

闲话

  • 历史课把课本讲完了。
  • 中午下课的时候又开始下雨。
  • 晚新闻进行高考、非高考、奥赛科目的评教。
  • 晚三的时候班主任把 @HANGRY_sol@wkh2008@Charlie_ljk@ccxswl 和我叫了出去谈话,问了下回班上课后 \(whk\) 补得怎么样,这次考试打算达到一个什么样的目标,提了下最近上课暴露的问题,还有虽然他从我们教练那里得知我们可能高二拿个省一就知足了,没什么心气再去冲省队了,但 \(whk\) 还是得重视起来。

4.22

闲话

  • 教室的饮水机修好了。
  • 临吃晚饭前班长开会回来说明天早上整理完内务直接去吃饭, \(7:05\) 操场指定位置集合组织活动。
  • 晚上到机房后 \(miaomiao\) 说我们没事的时候就多打题,保持代码的手感。

做题纪要

luogu P6783 [Ynoi2008] rrusq

  • 考虑扫描线维护区间数颜色,对于每个元素记录最后一次被覆盖的矩形,使用 \(KD-Tree\) 加入和删除标记即可。

  • 但此时修改次数是 \(O(m \sqrt{n})\) 级别的但询问只有 \(O(q)\) ,不妨使用分块来平衡复杂度。

  • 为方便代码书写,可以采用线段树式的 \(KD-Tree\) 写法。

    点击查看代码
    struct node
    {
    	int pos[2],val;
    }a[100010];
    int L[100010],R[100010],pos[100010],c[100010],sum[100010],l[100010][2],r[100010][2],ans[1000010],klen,ksum,cur;
    vector<pair<int,int> >ask[1000010];
    void init(int n)
    {
    	klen=1600;  ksum=n/klen;
    	for(int i=1;i<=ksum;i++)
    	{
    		L[i]=R[i-1]+1;  R[i]=R[i-1]+klen;
    	}
    	if(R[ksum]<n)
    	{
    		ksum++;
    		L[ksum]=R[ksum-1]+1;  R[ksum]=n;
    	}
    	for(int i=1;i<=ksum;i++)  for(int j=L[i];j<=R[i];j++)  pos[j]=i;
    }
    void add(int l,int val)
    {
    	c[l]+=val;  sum[pos[l]]+=val;
    }
    int query(int l,int r)
    {
    	int ans=0;
    	if(pos[l]==pos[r])
    	{
    		for(int i=l;i<=r;i++)  ans+=c[i];
    	}
    	else
    	{
    		for(int i=l;i<=R[pos[l]];i++)  ans+=c[i];
    		for(int i=pos[l]+1;i<=pos[r]-1;i++)  ans+=sum[i];
    		for(int i=L[pos[r]];i<=r;i++)  ans+=c[i];
    	}
    	return ans;
    }
    bool cmp(node x,node y)
    {
    	return x.pos[cur]<y.pos[cur];
    }
    struct KDT
    {
    	struct kd_tree
    	{
    		int l,r,sum,val,cov,flag,mx[2],mn[2];
    	}tree[400010];
    	#define lson(rt) (rt<<1)
    	#define rson(rt) (rt<<1|1)
    	void pushup(int rt)
    	{
    		tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
    		for(int i=0;i<=1;i++)
    		{
    			tree[rt].mx[i]=max(tree[lson(rt)].mx[i],tree[rson(rt)].mx[i]);
    			tree[rt].mn[i]=min(tree[lson(rt)].mn[i],tree[rson(rt)].mn[i]);
    		}
    	}
    	void build(int rt,int l,int r,int dir)
    	{
    		tree[rt].l=l;  tree[rt].r=r;
    		if(l==r)
    		{
    			tree[rt].cov=tree[rt].flag=0;
    			tree[rt].sum=a[l].val;
    			for(int i=0;i<=1;i++)	tree[rt].mx[i]=tree[rt].mn[i]=a[l].pos[i];
    			return;
    		}
    		int mid=(l+r)/2;  cur=dir;
    		nth_element(a+l,a+mid,a+r+1,cmp);
    		build(lson(rt),l,mid,dir^1);  build(rson(rt),mid+1,r,dir^1);
    		pushup(rt);
    	}
    	void pushlazy(int rt,int cov,int flag,int op)
    	{
    		if(op==-1)
    		{
    			add(tree[rt].cov,-tree[rt].sum);
    			tree[rt].cov=cov;  tree[rt].flag=flag;
    		}
    		else
    		{
    			tree[rt].cov=cov;  tree[rt].flag=flag;
    			add(tree[rt].cov,tree[rt].sum);
    		}
    	}
    	void pushdown(int rt)
    	{
    		if(tree[rt].cov!=0)
    		{
    			pushlazy(lson(rt),tree[rt].cov,1,-1);
    			pushlazy(rson(rt),tree[rt].cov,1,-1);
    			tree[rt].cov=0;
    		}
    	}
    	void clear(int rt)
    	{
    		if(tree[rt].flag==0)  return;
    		pushlazy(rt,0,0,-1);
    		if(tree[rt].l==tree[rt].r)  return;
    		clear(lson(rt));  clear(rson(rt));
    	}
    	void update(int rt,int l[2],int r[2],int cov)
    	{
    		for(int i=0;i<=1;i++)  if(l[i]>tree[rt].mx[i]||r[i]<tree[rt].mn[i])  return;
    		int flag=1;
    		for(int i=0;i<=1;i++)  flag&=(l[i]<=tree[rt].mn[i]&&tree[rt].mx[i]<=r[i]);
    		if(flag==1)
    		{
    			clear(rt);  pushlazy(rt,cov,1,1);
    			return;
    		}
    		pushdown(rt);  tree[rt].flag=1;
    		if(tree[rt].l==tree[rt].r)  return;
    		update(lson(rt),l,r,cov);  update(rson(rt),l,r,cov);
    	}
    }K;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,q,x,y,i,j;
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].pos[1],&a[i].val);  a[i].pos[0]=i;
    	}
    	scanf("%d",&m);  K.build(1,1,n,0);  init(m);
    	for(i=1;i<=m;i++)  scanf("%d%d%d%d",&l[i][0],&r[i][0],&l[i][1],&r[i][1]);
    	scanf("%d",&q);
    	for(i=1;i<=q;i++)
    	{
    		scanf("%d%d",&x,&y);
    		ask[y].push_back(make_pair(x,i));
    	}
    	for(i=1;i<=m;i++)
    	{
    		K.update(1,l[i],r[i],i);
    		for(j=0;j<ask[i].size();j++)  ans[ask[i][j].second]=query(ask[i][j].first,i);
    	}
    	for(i=1;i<=q;i++)  printf("%d\n",ans[i]);
    	return 0;
    }
    

4.23

闲话

  • 早饭后在操场举行世界读书日主题活动。
  • 语文和地理的换课比较神秘。
  • 晚三进行共青团员的选举。

4.24

闲话

做题纪要

luogu P5298 [PKUWC2018] Minimax

  • 注意到每个结点最多有两个子节点且叶子节点的权值互不相同。

  • 合并过程中概率的转移是一个含有前后缀和的形式且可以分成若干个部分逐层下传,在合并过程中直至遇到两棵树中有一个为空节点即可。

    点击查看代码
    const ll p=998244353;
    ll fa[300010],du[300010],a[300010],cnt=0;
    vector<ll>e[300010];
    struct SMT
    {
    	ll root[300010],rt_sum;
    	struct SegmentTree
    	{
    		ll ls,rs,sum,lazy;
    	}tree[300010<<5];
    	#define lson(rt) (tree[rt].ls)
    	#define rson(rt) (tree[rt].rs)
    	ll build_rt()
    	{
    		rt_sum++;  ll rt=rt_sum;
    		lson(rt)=rson(rt)=tree[rt].sum=0;
    		tree[rt].lazy=1;
    		return rt;
    	}
    	void pushup(ll rt)
    	{
    		tree[rt].sum=(tree[lson(rt)].sum+tree[rson(rt)].sum)%p;
    	}
    	void pushlazy(ll rt,ll lazy)
    	{
    		tree[rt].sum=tree[rt].sum*lazy%p;
    		tree[rt].lazy=tree[rt].lazy*lazy%p;
    	}
    	void pushdown(ll rt)
    	{
    		pushlazy(lson(rt),tree[rt].lazy);  pushlazy(rson(rt),tree[rt].lazy);
    		tree[rt].lazy=1;
    	}
    	void update(ll &rt,ll l,ll r,ll pos)
    	{
    		if(rt==0)  rt=build_rt();
    		if(l==r) 
    		{
    			tree[rt].sum=1;
    			return;
    		}
    		pushdown(rt);
    		ll mid=(l+r)/2;
    		if(pos<=mid)  update(lson(rt),l,mid,pos);
    		else  update(rson(rt),mid+1,r,pos);
    		pushup(rt);
    	}
    	ll merge(ll rt1,ll rt2,ll val1,ll val2,ll val)
    	{
    		if(rt1==0&&rt2==0)  return 0;
    		if(rt1==0)
    		{
    			pushlazy(rt2,val2);
    			return rt2;
    		}
    		if(rt2==0)
    		{
    			pushlazy(rt1,val1);
    			return rt1;
    		}
    		pushdown(rt1);  pushdown(rt2);
    		ll s1=tree[lson(rt1)].sum,s2=tree[lson(rt2)].sum;
    		lson(rt1)=merge(lson(rt1),lson(rt2),(val1+(1-val+p)%p*tree[rson(rt2)].sum%p)%p,(val2+(1-val+p)%p*tree[rson(rt1)].sum%p)%p,val);
    		rson(rt1)=merge(rson(rt1),rson(rt2),(val1+val*s2%p)%p,(val2+val*s1%p)%p,val);
    		pushup(rt1);
    		return rt1;
    	}
    	ll query(ll rt,ll l,ll r)
    	{
    		if(rt==0)  return 0;
    		if(l==r)
    		{
    			cnt++;
    			return cnt*l%p*tree[rt].sum%p*tree[rt].sum%p;
    		}
    		pushdown(rt);
    		ll mid=(l+r)/2;
    		return (query(lson(rt),l,mid)+query(rson(rt),mid+1,r))%p;
    	}
    }T;
    void add(ll u,ll v)
    {
    	e[u].push_back(v);
    }
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    void dfs(ll x)
    {
    	if(e[x].size()==0)  T.update(T.root[x],1,1000000000,a[x]);
    	else
    	{
    		dfs(e[x][0]);  T.root[x]=T.root[e[x][0]];
    		if(e[x].size()==2)
    		{
    			dfs(e[x][1]);  
    			T.root[x]=T.merge(T.root[x],T.root[e[x][1]],0,0,a[x]);
    		}
    	}
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,inv=qpow(10000,p-2,p),i;
    	cin>>n;
    	for(i=1;i<=n;i++) 
    	{
    		cin>>fa[i];  add(fa[i],i);
    	}
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		if(e[i].size()!=0)  a[i]=a[i]*inv%p;
    	}
    	dfs(1);
    	cout<<T.query(T.root[1],1,1000000000)<<endl;
    	return 0;
    }
    

4.25

闲话

  • 因临时换课,遂信息课“侵占”了语文课。
  • 因邻近学考,遂阅览课班主任改成政治了。最终把必修三讲完了,必修四只勾学案也才勾了三四课。
  • 晚上英语的全真模拟给作文一共留了 \(70 \min\) 但实际写的还是依托答辩。

4.26

闲话

  • 周测。

4.27

闲话

  • 讲评。
  • 收拾考场时才知道上次考试没给我们报缺考,这次就不用去滏阳楼考试了。

4.28

闲话

  • 进场后发现所在教室和我们班教室大小差不多,但有 \(71\) 名学生。
  • 墙上的表快 \(2 \min\) ,没有铃声提醒考生收拾桌面、准备进场,不是很习惯。
  • 语文基础好难;作文感觉写跑题了,分论点与材料都符合,但中心论点就有点远了,最后能拿 \(45pts\) 也是没想到的。 \(121pts\)
  • 物理吸取教训,多选先当单选做,给大题留了 \(40 \min\) ,拼尽全力都写完了后又去补多选,但计算失误若干;实验错了一个空起因是当初背错了结论,虽一直觉得不符合直觉但没深究;涂卡笔和橡皮不太给力,有一个选项没擦干净。\(72pts\) 还能 \(1700\) 多名。
  • 英语听力比较魔幻,完型直接错了一半;给小、大作文留了 \(55 \min\) ,实际还是写了依托答辩 \(8pts+15pts\)\(112pts\)
  • 数学选择的立体几何有些困难,填空有个题忘处理切去的圆锥的影响了;开始写大题的时候还剩 \(1h\) ,且第一道大题耗得时间太长,遂调整了开题顺序,结果又算错数了,最后 \(5 \min\) 把倒数第二道大题的二、三问做出来了,但四等分点写成了三等分点、圆锥体积忘乘 \(\frac{1}{3}\) 遂努力作废。 \(100pts\) 被批还不如文实考得高。

4.29

闲话

  • 考化学时不会的还是很多,最终 \(75pts \to 77pts\) ,荣获班级倒数。
  • 考生物时看错表了以为 \(10:15\) 结束,但因为当时已经写到最后一道大题了遂影响不是很大。 \(91pts \to 91pts\)
  • 考完收拾了下教室就上公自了,班主任说下午和晚上的学科自习全改成奥赛。
  • 下午到机房后 \(miaomiao\) 对其他人说距离高考集训也就剩一个多月了,等放假回来基本就到新的班级,现在其他奥赛教练对于升高二是否要接着学奥赛而犹豫不决的主张先稳住,但他觉得这种情况对于整个团队的发展就像一个定时炸弹,还不如现在就即使剔除掉,比如正常情况下奥赛课是不允许学 \(whk\) 的但他还是让部分人在机房学 \(whk\) ,等到暑假的时候就硬性要求不允许把 \(whk\) 作业带到机房,那时候我们的时间就正式属于他了,也会找之前的学长回来进行讲课。先提前说好了,到时候谁先打破这个规定,他就先干谁。多和家长交流下以后的升学、就业等发展规划,部分家长的态度也可以告诉他,对待奥赛的态度就不要一直晃悠了,否则自己就会习惯这种想学的时候就打打题,不想写题的时候就水水博客,刷讨论区,看别人写的流水账,然后自己也写份流水账的模式。只管升学的话,最低也得银牌,省一没啥用,但是大学转专业、申报奖学金时不同高校对此的政策都不一样。 \(NOIP\) 后退役对 \(whk\) 没啥影响,可能还会有帮助,毕竟到那时候也有一定的底子了,反正学校会安排补课,但实际补到什么程度主要取决于我们自己写不写作业,只听课不写作业的效率是非常低的。学知识点时要学踏实,不要一味追求快,前几届也出现过这种贪多嚼不烂的现象。

做题纪要

luogu P5158 【模板】多项式快速插值

  • 拉格朗日插值求系数

    • \(g(x)=\prod\limits_{i=1}^{n}(x-x_{i})\) 。然后直接快进到 \(f(x)=\sum\limits_{i=1}^{n}\dfrac{y_{i}}{\prod\limits_{j \ne i}(x_{i}-x_{j})} \times \dfrac{g(x)}{x-x_{i}}\)
    • \(h_{i}(x)=\dfrac{g(x)}{x-x_{i}}\) 后有 \([x^{k}]f=\sum\limits_{i=1}^{n}\dfrac{y_{i}}{\prod\limits_{j \ne i}(x_{i}-x_{j})}[x^{k}]h_{i}\) 。此时只需要处理出后面 \(\dfrac{g(x)}{x-x_{i}}\) 的各项系数即可。
    • \(h_{i}(x)\) 移项后有 \((x-x_{i})h_{i}(x)=g(x)\) ,相应地有 \([x^{k-1}]h_{i}-x_{i}[x^{k}]h_{i}=[x^{k}]g\) ,即 \([x^{k}]h_{i}=\dfrac{[x^{k-1}]h_{i}-[x^{k}]g}{x_{i}}\)
    • \([x^{k}]g\) 可以手动展开求解,时间复杂度为 \(O(n^{2})\)
    • 特判当 \(x_{i}=0\) 时直接降幂即可。
  • 注意下标从 \(0/1\) 开始导致的实际系数问题和调试难度。

    点击查看代码
    const ll p=998244353;
    ll x[100010],y[100010],c[100010],f[100010],g[100010];
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    void lagrange(ll n)
    {
    	c[1]=1;// 对应实际零次幂的系数,以下同理
    	for(ll i=1;i<=n;i++)
    	{
    		for(ll j=i+1;j>=1;j--)  c[j]=(c[j]*(p-x[i])%p+c[j-1])%p;
    	}
    	for(ll i=1;i<=n;i++)
    	{
    		ll inv=qpow(x[i],p-2,p),val=1;
    		for(ll j=1;j<=n;j++)  if(i!=j)  val=val*(x[i]-x[j]+p)%p;
    		val=qpow(val,p-2,p)*y[i]%p;
    		if(inv==0)  for(ll j=1;j<=n;j++)  f[j]=(f[j]+val*g[j+1]%p)%p;
    		else  for(ll j=1;j<=n;j++)
    		{
    			g[j]=inv*(g[j-1]-c[j]+p)%p;
    			f[j]=(f[j]+val*g[j]%p)%p;
    		}
    	}
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,i;
    	cin>>n; 
    	for(i=1;i<=n;i++)  cin>>x[i]>>y[i];
    	lagrange(n);
    	for(i=1;i<=n;i++)  cout<<f[i]<<" ";
    	return 0;
    }
    

luogu P6271 [湖北省队互测2014] 一个人的数论

  • 推式子,有 \(\begin{aligned} \sum\limits_{i=1}^{n}[\gcd(i,n)=1]i^{m} &=\sum\limits_{d|n}\mu(d)\sum\limits_{i=1}^{n}[d|i]i^{m} \\ &=\sum\limits_{d|n}\mu(d)d^{m}\sum\limits_{i=1}^{\frac{n}{d}}i^{m} \end{aligned}\)

  • 后面 \(\sum\limits_{i=1}^{\frac{n}{d}}i^{m}\) 的部分是一个 \(m+1\) 次多项式,这里可以暴力插出各项系数,记为 \(f(n)=\sum\limits_{i=0}^{m+1}f_{i}n^{i}\)

  • 现在就只需要处理 \(\sum\limits_{d|n}\mu(d)d^{m-i}\) 了。因 \(\mu(d)d^{m-i}\) 是一个积性函数,进一步整理得到 \(\prod\limits_{j=1}^{w}\sum\limits_{k=0}^{\alpha_{j}}\mu(p_{j}^{k})p_{j}^{k(m-i)}\)

  • 又因为 \(k\) 至多枚举到 \(1\) ,有 \(\sum\limits_{i=0}^{m+1}f_{i}n^{i}\prod\limits_{j=1}^{w}(1-p_{j}^{m-i})\) 即为所求。

    点击查看代码
    const ll p=1000000007;
    ll a[1010],inv[1010],x[110],y[110],c[110],f[110],g[110];
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    void lagrange(ll n)
    {
    	c[1]=1;
    	for(ll i=1;i<=n;i++)  for(ll j=i+1;j>=1;j--)
    		c[j]=(c[j]*(p-x[i])%p+c[j-1])%p;
    	for(ll i=1;i<=n;i++)
    	{
    		ll inv=qpow(x[i],p-2,p),val=1;
    		for(ll j=1;j<=n;j++)  if(i!=j)  val=val*(x[i]-x[j]+p)%p;
    		val=qpow(val,p-2,p)%p*y[i]%p;
    		if(inv==0)  for(ll j=1;j<=n;j++)  f[j]=(f[j]+val*g[j+1]%p)%p;
    		else  for(ll j=1;j<=n;j++)
    		{
    			g[j]=inv*(g[j-1]-c[j]+p)%p;
    			f[j]=(f[j]+val*g[j]%p)%p;
    		}
    	}
    }
    
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll w,m,n=1,b,ans=0,mul=0,i,j,k;
    	cin>>m>>w;
    	for(i=1;i<=w;i++)
    	{
    		cin>>a[i]>>b;  n=n*qpow(a[i],b,p)%p;
    		inv[i]=qpow(a[i],p-2,p);  a[i]=qpow(a[i],m,p);
    	}
    	for(i=1;i<=m+2;i++)
    	{
    		x[i]=i;  y[i]=(y[i-1]+qpow(i,m,p))%p;
    	}
    	lagrange(m+2);
    	for(i=k=1;i<=m+2;i++,k=k*n%p)
    	{
    		mul=1;
    		for(j=1;j<=w;j++)
    		{
    			mul=mul*(1-a[j]+p)%p;
    			a[j]=a[j]*inv[j]%p;
    		}
    		ans=(ans+f[i]*k%p*mul%p)%p;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

LibreOJ 6024. XLkxc

  • 合并后发现是一个形如函数嵌套的样子,有 \(\begin{aligned} g(x) &=\sum\limits_{i=1}^{x}f_{k}(i) \\ &=\sum\limits_{i=1}^{x}\sum\limits_{j=0}^{k+1}f_{k,j}i^{j} \\ &=\sum\limits_{i=0}^{k+1}f_{k,i}\sum\limits_{j=1}^{x}j^{i} \\ &=\sum\limits_{i=0}^{k+1}f_{k,i}\sum\limits_{j=0}^{i+1}f_{i,j}x^{j} \\ &=\sum\limits_{i=0}^{k+2}x^{i}\sum\limits_{j=0}^{k+1}f_{k,j}f_{j,i} \end{aligned}\) 也是 \(k+2\) 次多项式。

  • \(\begin{aligned} h_{k}(x) &=\sum\limits_{i=0}^{n}(x+id)^{k} \\ &=\sum\limits_{i=0}^{n}\sum\limits_{j=0}^{k}\dbinom{k}{j}x^{j}(id)^{k-j} \\ &=\sum\limits_{i=0}^{k}\dbinom{k}{i}x^{i}d^{k-i}\sum\limits_{j=0}^{n}j^{k-i} \\ &=\sum\limits_{i=0}^{k}\dbinom{k}{i}x^{i}d^{k-i} f_{k-i}(n) \end{aligned}\) ,则 \(\sum\limits_{i=0}^{k+2}g_{i}h_{i}(a)\) 即为所求。

    • 特别地,本题中要求 \(0^{0}=1\)
    点击查看代码
    const ll p=1234567891;
    ll C[150][150],mi[2][150];
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    void init(ll n)
    {
    	C[0][0]=C[1][0]=C[1][1]=1;
    	for(ll i=2;i<=n;i++)
    	{
    		C[i][0]=1;
    		for(ll j=1;j<=i;j++)  C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
    	}
    }
    struct lagrange
    {
    	ll x[150],y[150],c[150],f[150],g[150],deg;
    	void init(ll k)
    	{
    		deg=k+1;
    		for(ll i=1;i<=deg+1;i++)  
    		{
    			x[i]=i;  y[i]=(y[i-1]+qpow(i,k,p))%p;
    		}
    		c[1]=1;
    		for(ll i=1;i<=deg+1;i++)  for(ll j=i+1;j>=1;j--)
    			c[j]=(c[j]*(p-x[i])%p+c[j-1])%p;
    		for(ll i=1;i<=deg+1;i++)
    		{
    			ll inv=qpow(x[i],p-2,p),val=1;
    			for(ll j=1;j<=deg+1;j++)  if(i!=j)  val=val*(x[i]-x[j]+p)%p;
    			val=qpow(val,p-2,p)%p*y[i]%p;
    			if(inv==0)  for(ll j=1;j<=deg+1;j++)  f[j]=(f[j]+val*g[j+1]%p)%p;
    			else  for(ll j=1;j<=deg+1;j++)
    			{
    				g[j]=inv*(g[j-1]-c[j]+p)%p;
    				f[j]=(f[j]+val*g[j]%p)%p;
    			}
    		}
    	}
    	ll query(ll x)
    	{
    		ll ans=0;
    		for(ll i=1,j=1;i<=deg+1;i++,j=j*x%p)  ans=(ans+f[i]*j%p)%p;
    		return ans;
    	}
    }L[150];
    ll query(ll n,ll k)
    {
    	ll ans=0;
    	for(ll i=0;i<=k;i++)  
    	{
    		ans=(ans+C[k][i]*mi[0][i]%p*mi[1][k-i]%p)%p;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll t,k,a,n,d,ans,sum,i,j;
    	cin>>t;  init(130);
    	for(i=0;i<=130;i++)  L[i].init(i);
    	for(;t>=1;t--)
    	{
    		cin>>k>>a>>n>>d;  ans=sum=0;
    		mi[0][0]=mi[1][0]=1;
    		for(i=1;i<=k+3;i++)
    		{
    			mi[0][i]=mi[0][i-1]*a%p;  mi[1][i]=mi[1][i-1]*d%p;
    		}
    		mi[1][0]=mi[1][0]*(n+1)%p;
    		for(i=1;i<=k+3;i++)  mi[1][i]=mi[1][i]*L[i].query(n)%p;
    		for(i=1;i<=k+3;i++)
    		{
    			sum=0;
    			for(j=max(1ll,i-1);j<=k+2;j++)  sum=(sum+L[k].f[j]*L[j-1].f[i]%p)%p;
    			ans=(ans+sum*query(n,i-1)%p)%p;
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    

luogu P4593 [TJOI2018] 教科书般的亵渎

  • 分段后拉格朗日插值求 \(\sum\limits i^{m}\) 即可。

    点击查看代码
    const ll p=1000000007;
    ll a[110],inv[110],jc_inv[110],y[110],pre[110],suf[110];
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    ll lagrange(ll n,ll _x)
    {
    	ll ans=0;
    	pre[0]=suf[n+1]=1;
    	for(ll i=1;i<=n;i++)  pre[i]=pre[i-1]*(_x-i+p)%p;
    	for(ll i=n;i>=1;i--)  suf[i]=suf[i+1]*(_x-i+p)%p;
    	for(ll i=1;i<=n;i++)
    	{
    		if((n-i)%2==0)  ans=(ans+jc_inv[i-1]*jc_inv[n-i]%p*pre[i-1]%p*suf[i+1]%p*y[i]%p)%p;
    		else  ans=(ans-jc_inv[i-1]*jc_inv[n-i]%p*pre[i-1]%p*suf[i+1]%p*y[i]%p+p)%p;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll t,n,m,ans,i,j;
    	cin>>t;
    	inv[0]=jc_inv[0]=1;
    	for(i=1;i<=100;i++)
    	{
    		inv[i]=qpow(i,p-2,p);
    		jc_inv[i]=jc_inv[i-1]*inv[i]%p;
    	}
    	for(;t>=1;t--)
    	{
    		cin>>n>>m;  ans=0;
    		for(i=1;i<=m;i++)  cin>>a[i];
    		m++;  a[m]=0;
    		sort(a+1,a+1+m);
    		for(i=1;i<=m+2;i++)  y[i]=(y[i-1]+qpow(i,m,p))%p;
    		for(i=1;i<=m;i++)
    		{
    			ans=(ans+((n-a[i]<=m+2)?y[n-a[i]]:lagrange(m+2,(n-a[i])%p)))%p;
    			for(j=i+1;j<=m;j++)  ans=(ans-qpow(a[j]-a[i],m,p)+p)%p;
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    

luogu P12385 [蓝桥杯 2023 省 Python B] 异或和

  • DFS 序

    点击查看代码
    struct node
    {
    	int nxt,to;
    }e[200010];
    int head[100010],a[100010],dfn[100010],out[100010],cnt=0,tot=0;
    void add(int u,int v)
    {
    	cnt++;  e[cnt]=(node){head[u],v};  head[u]=cnt;
    }
    void dfs(int x,int fa)
    {
    	tot++;  dfn[x]=tot;
    	for(int i=head[x];i!=0;i=e[i].nxt)  if(e[i].to!=fa)  dfs(e[i].to,x);
    	out[x]=tot;
    }
    struct BIT
    {
    	int c[100010];
    	int lowbit(int x)
    	{
    		return (x&(-x));
    	}
    	void add(int n,int x,int val)
    	{
    		for(int i=x;i<=n;i+=lowbit(i))  c[i]^=val;
    	}
    	int getsum(int x)
    	{
    		int ans=0;
    		for(int i=x;i>=1;i-=lowbit(i))  ans^=c[i];
    		return ans;
    	}
    }B;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,pd,u,v,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)  cin>>a[i];
    	for(i=1;i<=n-1;i++)
    	{
    		cin>>u>>v;
    		add(u,v);  add(v,u);
    	}
    	dfs(1,0);
    	for(i=1;i<=n;i++)  B.add(n,dfn[i],a[i]);
    	for(i=1;i<=m;i++)
    	{
    		cin>>pd>>u;
    		if(pd==1)
    		{
    			cin>>v;
    			B.add(n,dfn[u],a[u]);
    			a[u]=v;  B.add(n,dfn[u],a[u]);
    		}
    		else  cout<<(B.getsum(out[u])^B.getsum(dfn[u]-1))<<endl;
    	}
    	return 0;
    }
    

luogu P4463 [集训队互测 2012] calc

  • 不妨钦定 \(a\) 升序。

  • \(f_{i,j}\) 表示前 \(i\) 个数的值域为 \([1,j]\) 的贡献,有 \(f_{i,j}=f_{i,j-1}+f_{i-1,j-1}j\)

  • \(f_{i}\) 进行差分 \(g_{i,j}=f_{i,j}-f_{i,j-1}=f_{i-1,j-1}j\)\(g_{i,j}=j\sum\limits_{k=0}^{j-1}g_{i-1,k}\)

  • 观察到 \(g_{i,j}\) 是关于 \(j\)\(2i\) 次多项式,故 \(f_{i,j}\) 是关于 \(j\)\(2i+1\) 次多项式。

    • 前者可以进行数学归纳法证明。
    • 后者是因为若 \(f(x)\) 是关于 \(x\)\(n\) 次多项式则差分函数 \(g(x)=f(x)-f(x-1)\) 是关于 \(x\)\(n-1\) 次多项式,证明只需要将幂次相减展开即可。
    点击查看代码
    ll x[1010],y[1010],f[510][1010],p;
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)  ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    ll lagrange(ll n,ll _x)
    {
    	ll ans=0;
    	for(ll i=1;i<=n;i++)
    	{
    		ll up=y[i],down=1;
    		for(ll j=1;j<=n;j++)
    		{
    			if(i!=j)
    			{
    				up=up*(_x-x[j]+p)%p;
    				down=down*(x[i]-x[j]+p)%p;
    			}
    		}
    		ans=(ans+up*qpow(down,p-2,p)%p)%p;
    	}
    	return ans;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll k,n,m,jc=1,i,j;
    	cin>>k>>n>>p;  m=2*n+2;
    	for(i=0;i<=min(k,m);i++)  f[0][i]=1;
    	for(i=1;i<=n;i++)
    	{
    		jc=jc*i%p;
    		for(j=1;j<=min(k,m);j++)  f[i][j]=(f[i][j-1]+j*f[i-1][j-1]%p)%p;
    	}
    	for(i=1;i<=m;i++)  
    	{
    		x[i]=i;  y[i]=f[n][i];
    	}
    	cout<<jc*(k<=m?f[n][k]:lagrange(m,k))%p<<endl;
    	return 0;
    }
    

4.30

闲话

  • 讲评。
  • 晚新闻时班主任挨个念了下考试成绩和排名,说这次申报奖学金只针对参加考试的人来算。
  • 班主任说我们虽然是刚回班才一个多月,但也应该有巨大的进步,但实际进步没那么大,下次还得继续加油。
posted @ 2025-04-01 20:58  hzoi_Shadow  阅读(425)  评论(3)    收藏  举报
扩大
缩小