来自aakennes的新年祝福

来自aakennes的新年祝福

组题人: @aakennes

A P888. 字符串会上树 AC

  • 基础字符串。

    点击查看代码
    string s,t="",w="";
    map<string,string>f;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,q,i;
    	cin>>n>>q>>s;
    	for(i=0;i<=n-1;i++)
    	{
    		if(s[i]=='&')  
    		{
    			f[t]=w;
    			t="";
    		}
    		else  if(s[i]=='=')  w="";
    		else  if('0'<=s[i]&&s[i]<='9')  w+=s[i];
    		else  t+=s[i];
    	}
    	if(t!="")  f[t]=w;
    	for(i=1;i<=q;i++)
    	{
    		cin>>s;
    		if(f.find(s)==f.end())  cout<<"Does not exist."<<endl;
    		else  cout<<f[s]<<endl;
    	}
    	return 0;
    }
    

B P889. 挖宝石 AC

  • 背包循环移位转移。

    点击查看代码
    bool f[2][3010];
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,k,x,i,j;
    	cin>>n>>k;
    	for(i=1;i<=n;i++)
    	{
    		cin>>x;
    		x%=k;
    		for(j=0;j<=x-1;j++)  f[i&1][j]=f[(i-1)&1][j]|f[(i-1)&1][(j-x+k)%k];
    		for(j=x;j<=k-1;j++)  f[i&1][j]=f[(i-1)&1][j]|f[(i-1)&1][j-x];
    		f[i&1][x]=1;
    		if(f[i&1][0]==1)
    		{
    			cout<<"Yes"<<endl;
    			return 0;
    		}
    	}
    	cout<<"No"<<endl;
    	return 0;
    }
    

C P890. 电梯系统 AC

  • 手摸样例,得到一种构造方式形如

    1->2->3->4->5->6->7
    1---->3---->5---->7
    1------->4---->6
    1---------->5
    1------------->6
    1---------------->7
    	2---->4------->7
    	2------->5
    	2---------->6
    	2------------->7
    		3------>6
    		3------>7
    
  • 可知 i=1nmax(0,n(2i1)) 即为所求。

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

D P891. 打游戏 AC

  • 和求树的直径一样做即可。

    点击查看代码
    struct node
    {
    	ll nxt,to,w;
    }e[200010];
    ll head[100010],a[100010],f[100010],g[100010],len,cnt=0;
    void add(ll u,ll v,ll w)
    {
    	cnt++;
    	e[cnt].nxt=head[u];
    	e[cnt].to=v;
    	e[cnt].w=w;
    	head[u]=cnt;
    }
    void dfs(ll x,ll fa)
    {
    	for(ll i=head[x];i!=0;i=e[i].nxt)
    	{
    		if(e[i].to!=fa)
    		{
    			dfs(e[i].to,x);
    			if(f[e[i].to]-e[i].w>f[x])
    			{
    				g[x]=f[x];
    				f[x]=f[e[i].to]-e[i].w;
    			}
    			else
    			{
    				g[x]=max(g[x],f[e[i].to]-e[i].w);
    			}
    		}
    	}
    	f[x]+=a[x];
    	len=max(len,f[x]+g[x]);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,u,v,w,i;
    	cin>>n;
    	for(i=1;i<=n;i++)  cin>>a[i];
    	for(i=1;i<=n-1;i++)
    	{
    		cin>>u>>v>>w;
    		add(u,v,w);  add(v,u,w);
    	}
    	dfs(1,0);
    	cout<<len<<endl;
    	return 0;
    }
    

E P892. 魔法水晶 AC

  • 考虑建出最短路 DAG 后补全成原图并计数。

    点击查看代码
    const ll p=998244353;
    ll a[200010],cnt[200010];
    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("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,ans=1,i;
    	cin>>n;
    	for(i=1;i<=n;i++)  
    	{
    		cin>>a[i];
    		cnt[a[i]]++;
    	}
    	for(i=1;i<=n-1&&cnt[i]!=0;i++)  ans=ans*qpow((qpow(2,cnt[i-1],p)-1+p)%p,cnt[i],p)%p*qpow(2,cnt[i]*(cnt[i]-1)/2,p)%p;
    	for(;i<=n-1;i++)  if(cnt[i]!=0)  ans=0;
    	cout<<ans<<endl;
    	return 0;
    }
    

F P893. 随机数序列

  • 根据左右移位时不变的位置顺次求出其他位置。

    点击查看代码
    uint a[200010],t[50];
    pair<uint,uint>c[200010];
    uint random(uint& seed)
    {
    	seed ^= (seed << 16);
    	seed ^= (seed >> 5);
    	seed ^= (seed << 1);
    	return seed;
    }
    uint rev(uint x)
    {
    	for(int i=31;i>=0;i--)  t[i]=(x>>i)&1;
    	for(int i=1;i<=31;i++)  t[i]^=t[i-1];
    	for(int i=26;i>=0;i--)  t[i]^=t[i+5];
    	for(int i=16;i<=31;i++)  t[i]^=t[i-16];
    	x=0;
    	for(int i=31;i>=0;i--)  x=(x<<1)|t[i];
    	return x;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,i;
    	uint seed;
    	cin>>n;
    	for(i=1;i<=n;i++)  cin>>c[i].first>>c[i].second;
    	sort(c+1,c+1+n);
    	seed=a[c[1].first]=c[1].second;
    	for(i=c[1].first+1;i<=200000;i++)  a[i]=random(seed);
    	for(i=2;i<=n;i++)
    	{
    		if(a[c[i].first]!=c[i].second)
    		{
    			cout<<"no"<<endl;
    			return 0;
    		}
    	}
    	seed=c[1].second;
    	for(i=1;i<=c[1].first;i++)  seed=rev(seed);
    	cout<<seed<<endl;
    	return 0;
    }
    

G P894. 线段树改造 AC

  • 观察到循环移位 ij=(i+j+1)mod4 ,询问时的 +1 提出来最后再加。

    点击查看代码
    int a[200010];
    struct SMT
    {
    	struct SegmentTree
    	{
    		int len,sum,lazy;
    	}tree[800010];
    	#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)%4;
    	}
    	void build(int rt,int l,int r)
    	{
    		tree[rt].len=r-l+1;
    		if(l==r)
    		{
    			tree[rt].sum=a[l];
    			return;
    		}
    		int mid=(l+r)/2;
    		build(lson(rt),l,mid);
    		build(rson(rt),mid+1,r);
    		pushup(rt);
    	}
    	void pushlazy(int rt,int lazy)
    	{
    		tree[rt].lazy=(tree[rt].lazy+lazy)%4;
    		tree[rt].sum=(tree[rt].sum+lazy*tree[rt].len)%4;
    	}
    	void pushdown(int rt)
    	{
    		pushlazy(lson(rt),tree[rt].lazy);
    		pushlazy(rson(rt),tree[rt].lazy);
    		tree[rt].lazy=0;
    	}
    	void update(int rt,int l,int r,int x,int y,int val)
    	{
    		if(x<=l&&r<=y)
    		{
    			pushlazy(rt,val);
    			return;
    		}
    		pushdown(rt);
    		int mid=(l+r)/2;
    		if(x<=mid)  update(lson(rt),l,mid,x,y,val);
    		if(y>mid)  update(rson(rt),mid+1,r,x,y,val);
    		pushup(rt);
    	}
    	int query(int rt,int l,int r,int x,int y)
    	{
    		if(x<=l&&r<=y)  return tree[rt].sum;
    		pushdown(rt);
    		int mid=(l+r)/2;
    		if(y<=mid)  return query(lson(rt),l,mid,x,y);
    		if(x>mid)  return query(rson(rt),mid+1,r,x,y);
    		return (query(lson(rt),l,mid,x,y)+query(rson(rt),mid+1,r,x,y))%4;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,pd,l,r,x,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)  cin>>a[i];
    	T.build(1,1,n);
    	for(i=1;i<=m;i++)
    	{
    		cin>>pd>>l>>r;
    		if(pd==1)
    		{
    			cin>>x;
    			T.update(1,1,n,l,r,x+1);
    		}
    		else
    		{
    			cout<<(r-l+T.query(1,1,n,l,r))%4<<endl;
    		}
    	}
    	return 0;
    }
    

H P895. 赌博 AC

  • 题目要求找到 (x+f(f+1)2)modn=0 的最小正整数解,观察到有用的 f<nn2×105 ,枚举即可。

    点击查看代码
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll t,n,x,p,r,flag,i,j;
    	cin>>t;
    	for(j=1;j<=t;j++)
    	{
    		cin>>n>>x>>p;
    		flag=0;
    		for(i=1;i<=p&&i<=n-1;i++)
    		{
    			if((i*(i+1)/2%n+x)%n==0)
    			{
    				flag=1;
    				cout<<"Yes"<<endl;
    				break;
    			}
    		}
    		if(flag==0)  cout<<"No"<<endl;
    	}
    	return 0;
    }
    

I P896. 魔法水晶2

J P897. 对战

  • 原题: NOIP2024加赛1 T2 HZTG2081. 排列

  • 稍微卡卡常。

    点击查看代码
    const int p=998244353;
    int C[7010][7010],f[2][2][7010][20];
    int qadd(int a,int b)
    {
    	return a+b>=p?a+b-p:a+b;
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,tmp,tmp1,tmp2,i,j,k;
    	cin>>n>>m;
    	if(1.0*m>log2(n)+5.0)
    	{
    		cout<<0<<endl;
    	}
    	else
    	{
    		C[0][0]=C[1][0]=C[1][1]=1;
    		for(i=2;i<=n;i++)
    		{
    			C[i][0]=1;
    			for(j=1;j<=i;j++)
    			{
    				C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
    			}
    		}
    		for(i=0;i<=m;i++)
    		{
    			f[0][0][0][i]=f[0][1][0][i]=f[1][0][0][i]=f[1][1][0][i]=1;
    		}
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)
    			{
    				for(k=1;k<=i;k++)
    				{
    					tmp=C[i-1][k-1];
    					f[0][0][i][j]=qadd(f[0][0][i][j],(1ll*f[0][1][k-1][j]*f[1][0][i-k][j]%p)*tmp%p);
    					f[1][0][i][j]=qadd(f[1][0][i][j],(1ll*f[1][1][k-1][j-1]*f[1][0][i-k][j]%p)*tmp%p);
    					f[0][1][i][j]=qadd(f[0][1][i][j],(1ll*f[0][1][k-1][j]*f[1][1][i-k][j-1]%p)*tmp%p);
    					tmp1=(f[1][1][k-1][j]-f[1][1][k-1][j-1]+p)%p;
    					tmp2=(f[1][1][i-k][j]-f[1][1][i-k][j-1]+p)%p;
    					f[1][1][i][j]=qadd(f[1][1][i][j],((1ll*f[1][1][k-1][j]*f[1][1][i-k][j]%p-1ll*tmp1*tmp2%p+p)%p)*tmp%p);
    				}
    			}
    		}
    		cout<<(f[0][0][n][m]-f[0][0][n][m-1]+p)%p<<endl;
    	}
    	return 0;
    }
    

K P898. 交通网络

L P899. 疯狂的矩阵

M P900. 超级计算机

  • swap 被调用次数等价于全局逆序对数。

  • 弱化版: CF785E Anton and Permutation | luogu P1975 [国家集训队] 排队

  • 弱化版中树套树或分块的做法不适用于本题。

  • 考虑将连续的一段缩成一个点进行处理,离散化维护。

    点击查看代码
    const ll p=998244353;
    ll d[200010],x[200010],y[200010];
    map<ll,ll>a;
    map<ll,ll>::iterator it;
    struct BIT
    {
    	ll c[200010];
    	ll lowbit(ll x)
    	{
    		return (x&(-x));
    	}
    	void clear()
    	{
    		memset(c,0,sizeof(c));
    	}
    	void add(ll n,ll x,ll val)
    	{
    		for(ll i=x;i<=n;i+=lowbit(i))  c[i]+=val;
    	}
    	ll getsum(ll x)
    	{
    		ll ans=0;
    		for(ll i=x;i>=1;i-=lowbit(i))   ans+=c[i];
    		return ans;
    	}
    	ll query(ll l,ll r)
    	{
    		return l<=r?getsum(r)-getsum(l-1):0;
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	ll n,m,l,r,ans=0,i;
    	cin>>n>>m;
    	for(i=1;i<=m;i++)
    	{
    		cin>>l>>r;
    		if(l>r)  swap(l,r);
    		d[0]++;  d[d[0]]=l;
    		d[0]++;  d[d[0]]=r;
    		if(a.find(l)==a.end())  a[l]=l;
    		if(a.find(r)==a.end())  a[r]=r;
    		swap(a[l],a[r]);
    	}
    	sort(d+1,d+1+d[0]);  d[0]=unique(d+1,d+1+d[0])-(d+1);
    	m=0;
    	for(it=a.begin();it!=a.end();it++)  
    	{
    		m++;  x[m]=lower_bound(d+1,d+1+d[0],it->first)-d;   y[m]=lower_bound(d+1,d+1+d[0],it->second)-d;
    		ans=(ans+max(0ll,abs(it->second-it->first)-1))%p;
    	}
    	for(i=1;i<=m;i++)
    	{	
    		ans=(ans-T.query(min(x[i],y[i])+1,max(y[i],x[i])-1)+p)%p;
    		T.add(d[0],y[i],1);
    	}	
    	T.clear();
    	for(i=m;i>=1;i--)
    	{
    		ans=(ans-T.query(min(x[i],y[i])+1,max(y[i],x[i])-1)+T.getsum(y[i]-1)+p)%p;
    		T.add(d[0],y[i],1);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

N P901. 线段树改造2

  • 既然已经限制了 具有结合律,线段树直接维护即可。

  • 难点在于中缀表达式求值,建议先去写 luogu P10473 表达式计算4

    点击查看代码
    const int p=998244353;
    int a[200010],len;
    char s[60];
    stack<int>s1;
    stack<char>s2;
    int val(char x)
    {
    	if(x=='(')  return 0;
    	if(x=='+'||x=='-')  return 1;
    	if(x=='*')  return 2;
    	return -1;
    }
    void work()
    {  
    	int a=s1.top();  s1.pop();
    	int b=s1.top();  s1.pop();
    	char c=s2.top();  s2.pop();
    	if(c=='+')  s1.push((b+a)%p);
    	if(c=='-')  s1.push((b-a+p)%p);
    	if(c=='*')  s1.push(1ll*b*a%p);
    }
    int ask(int x,int y)
    {
    	int tmp=0,flag=0;
    	for(int i=1;i<=len;i++)
    	{
    		if(('0'<=s[i]&&s[i]<='9')||s[i]=='a'||s[i]=='b')  
    		{
    			if('0'<=s[i]&&s[i]<='9')  tmp=(tmp*10%p+s[i]-'0')%p;
    			else tmp=(s[i]=='a')?x:y;
    			flag=1;
    			if(i==len)  s1.push(tmp);
    		}
    		else  
    		{
    			if(flag==1)
    			{
    				s1.push(tmp);
    				tmp=flag=0;
    			}
    			if(s[i]=='(')  s2.push(s[i]);
    			else  if(s[i]==')')  
    			{
    				while(s2.top()!='(')  work();
    				s2.pop();
    			}
    			else
    			{
    				while(s2.empty()==0&&val(s2.top())>=val(s[i]))  work();
    				s2.push(s[i]);
    			}
    		}
    		if(i==len)  while(s2.empty()==0)  work();
    	}
    	return s1.top();
    }
    struct SMT
    {
    	struct SegmentTree
    	{
    		int sum;
    	}tree[800010];
    	#define lson(rt) (rt<<1)
    	#define rson(rt) (rt<<1|1)
    	void pushup(int rt)
    	{
    		tree[rt].sum=ask(tree[lson(rt)].sum,tree[rson(rt)].sum);
    	}
    	void build(int rt,int l,int r)
    	{
    		if(l==r)
    		{
    			tree[rt].sum=a[l];
    			return;
    		}
    		int mid=(l+r)/2;
    		build(lson(rt),l,mid);
    		build(rson(rt),mid+1,r);
    		pushup(rt);
    	}
    	void update(int rt,int l,int r,int pos,int val)
    	{
    		if(l==r)
    		{
    			tree[rt].sum=ask(tree[rt].sum,val);
    			return;
    		}
    		int mid=(l+r)/2;
    		if(pos<=mid)  update(lson(rt),l,mid,pos,val);
    		else  update(rson(rt),mid+1,r,pos,val);
    		pushup(rt);
    	}
    	int query(int rt,int l,int r,int x,int y)
    	{
    		if(x<=l&&r<=y)  return tree[rt].sum;
    		int mid=(l+r)/2;
    		if(y<=mid)  return query(lson(rt),l,mid,x,y);
    		if(x>mid)  return query(rson(rt),mid+1,r,x,y);
    		return ask(query(lson(rt),l,mid,x,y),query(rson(rt),mid+1,r,x,y));
    	}
    }T;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("in.in","r",stdin);
    	freopen("out.out","w",stdout);
    #endif
    	int n,m,pd,l,r,i;
    	cin>>(s+1)>>n>>m;
    	len=strlen(s+1);
    	for(i=1;i<=n;i++)  cin>>a[i];
    	T.build(1,1,n);
    	for(i=1;i<=m;i++)
    	{
    		cin>>pd>>l>>r;
    		if(pd==1)
    		{
    			T.update(1,1,n,l,r);
    		}
    		else
    		{
    			cout<<T.query(1,1,n,l,r)<<endl;
    		}
    	}
    	return 0;
    }
    

O P902. 水果店

总结

  • 开题顺序: DAGBCEH
  • F 题罚坐两小时推逆运算没推出来。

后记

  • 题目中错别字较多,部分定义冗杂且陈述不清,存在歧义

  • H 数据范围分成了两部分,一半在输入格式里,一半在提升里。

  • O 因之前基本都写过遂找 huge 删了,题目背景留作存档。

posted @   hzoi_Shadow  阅读(64)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
扩大
缩小
点击右上角即可分享
微信分享提示