CSP13

wlesq發表於2024-08-02

T1

image
本來是道狀壓簽到題,看成博弈論了,其實是不對的,為什麼不對,建圖時是存在環的情況的,所以不能建一棵樹後跑\(sg\)函式
所以根據資料範圍,我們可以狀壓,這就很簡單了,每一次繼承的狀態為子狀態相反的狀態(不要試圖只表示贏得狀態)

考試程式碼(41,43)pts
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
const int N = 20;
int n;
char s[N][20];
bool vis[N];
struct e
{
	int u,to,next;
}edge[N*N];int head[N],cnt;
void add(int u,int v)
{
	edge[++cnt].u=u;
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
void g(int id)
{
	vis[id]=1;
	char tar=s[id][strlen(s[id]+1)];
	// cout<<id<<" "<<(char)tar<<endl;
	queue <int> q;
	for(int i=1;i<=n;i++)
	{
		if(vis[i]||s[i][1]!=tar)continue;
		// cout<<id<<" "<<i<<endl;
		add(id,i);add(i,id);
		vis[i]=1;q.push(i);
	}
	while(q.size())
	{
		g(q.front());
		q.pop();
	}
}
int fx[N];
bool dfs(int u,int f,int dep)
{
	bool lf=1;
	bool tm=0;
	for(int i=head[u];i;i=edge[i].next)
	{
		int to=edge[i].to;
		if(to==f)continue;
		// res=dfs(to,u,dep+1);
		bool res=dfs(to,u,dep+1);
		if(!res&&((dep+1)%2)==0)
		{
			// cout<<"*****"<<endl;
			tm=0;
			return 0;
		}
		if(res&&((dep+1)%2)==1)
		{
			tm=1;
			return 1;
		}
		// tm|=res;
		lf=0;
	}
	if(lf)
	{
		return (dep&1);
	}
	return tm;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>(s[i]+1);
	}
	// cout<<len<<endl;
	bool fr=0;
	for(int i=1;i<=n;i++)
	{
		// cout<<"********"<<endl;
		memset(vis,0,sizeof vis);
		memset(head,0,sizeof head);cnt=0;
		memset(edge,0,sizeof edge);
		g(i);
		fr=dfs(i,0,1);
		if(fr)
		{
			break;
		}
	}
	if(fr)cout<<"First"<<endl;
	else cout<<"Second"<<endl;
	return 0;
}
狀壓
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
const int N = 18;
int n;
char s[N][20];
bool vis[N];
int dp[(1<<16)+5][N];
bool dfs(ll zt,int lst)
{
	
	if(~dp[zt][lst])return dp[zt][lst];
	// cout<<bitset<16>(zt)<<" "<<lst<<endl;
	char tar=s[lst][strlen(s[lst]+1)];
	bool win=0,lf=1;
	int cnt=0;
	for(int i=0;i<n;i++)
	{
		if(zt&(1<<i))cnt++;
	}
	for(ll i=1;i<=n;i++)
	{	
		if((zt&(1ll<<(i-1)))||tar!=s[i][1])continue;
		lf=0;
		win|=(1-dfs(zt|(1ll<<(i-1)),i));
	}
	if(lf)win=1;
	return dp[zt][lst]=win;
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>(s[i]+1);
	}
	// cout<<len<<endl;
	bool fr=0;
	for(int i=1;i<=n;i++)
	{
		// cout<<"********"<<endl;
		// memset(vis,0,sizeof vis);
		// memset(head,0,sizeof head);cnt=0;
		memset(dp,-1,sizeof dp);
		// g(i);
		fr=dfs(1ll<<(i-1),i);
		if(fr)
		{
			break;
		}
	}
	if(fr)cout<<"First"<<endl;
	else cout<<"Second"<<endl;
	return 0;
}

T2

image
構造題,首先我們可以把\(2至n\)個點與\(1\)進行詢問,這樣我們知道每個點所處的深度,然後依次遍歷每一層,發現最多\(10到11\)層,我們肯定要拿當前要知道位置的點\(u\)與上一層的點\(y\)詢問,但還是不知道具體位置,我們可以利用重鏈剖分的性質,發現\(dep_x+dep_y-2\times dep_{lca(x,y)}=dis_{query}\),所以我們可以確定\(lca\)的深度且它一定在當前子樹根節點的重鏈上,我們從根節點開始往下找,\(y\)即為根節點重鏈的最底端點,每次\(dfs\)即可

點選檢視程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
const int N = 3005;
int n,fa[N],ch[N][2],bot[N];
vector <int> dis[N],edge[N];
bool vis[N];
void add(int u,int v)
{
	edge[u].pb(v);edge[v].pb(u);
	fa[v]=u;
	if(ch[u][0])ch[u][1]=v;
	else ch[u][0]=v;
}
int tg,num;
vector <int> may;
int dep[N],dfn[N],sz[N];
int ask(int u,int v)
{
	cout<<"? "<<u<<" "<<v<<endl;
	cout.flush();int de;
	cin>>de;
	return de;
}
void dfs(int u)
{
	if(!u)return;
	sz[u]=1;bot[u]=u;
	if(ch[u][0])
	{
		dfs(ch[u][0]);
		sz[u]+=sz[ch[u][0]];
	}
	if(ch[u][1])
	{
		dfs(ch[u][1]);
		sz[u]+=sz[ch[u][1]];
		if(sz[ch[u][1]]>sz[ch[u][0]])swap(ch[u][0],ch[u][1]);		
	}
	if(ch[u][0])bot[u]=bot[ch[u][0]];
	return ;
}
void solve(int u)
{
	int y=1;
	while(dep[y]!=dep[u]-1)
	{
		int de=ask(u,bot[y]);
		// break;
		int lca_dis=(dep[bot[y]]+dep[u]-de)/2;
		while(dep[y]<lca_dis)y=ch[y][0];
		if(dep[y]==dep[u]-1)break;
		y=ch[y][1];
	}
	add(y,u);
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n;
	int de,mx=0;
	// cout<<"&&&&&&&"<<endl;
	for(int i=2;i<=n;i++)
	{
		de=ask(1,i);
		// cout<<de<<endl;
		mx=max(mx,de);
		dis[de].push_back(i);	
		dep[i]=de;
	}
	for(int i=1;i<=mx;i++)
	{
		dfs(1);
		for(auto p:dis[i])
		{
			solve(p);
		}
	}
	cout<<"! ";
	for(int i=2;i<=n;i++)cout<<fa[i]<<" ";
	cout<<endl;
	cout.flush();
	return 0;
}

T3
image

回滾莫隊能過
細節,用\(vector\)\(clear\)以後要\(resize\),這個比較慢,建議換陣列

點選檢視程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
// #define int long long
const int N = 4E4+5,M=2e5+5;
ll h[N],w[N],n,m;ll ans[M],sq,num;
int st[N],en[N],bl[N];
ll f[205][205];
vector <ll> dp(205,0);
struct qu
{
	ll l,r,t,id;
	bool operator < (const qu& A)const
	{
		return bl[l]==bl[A.l]?r<A.r:l<A.l;
	}
}q[M];
inline void clear()
{
	for(int i=0;i<=200;i++)dp[i]&=0;
}
ll dp_solve(int l,int r,int t)
{
	if(l>r)return 0;
	for(int i=l;i<=r;i++)
	{
		for(int j=t;j>=h[i];j--)
			dp[j]=max(dp[j],dp[j-h[i]]+w[i]);
	}
	return dp[t];
}
void init()
{
	for(int i=1;i<=num;i++)
	{
		for(int j=st[i];j<=en[i];j++)
		{
			for(int t=200;t>=h[j];t--)
				f[i][t]=max(f[i][t],f[i][t-h[j]]+w[j]);
		}
	}
}
ll force(int l,int r,int t)
{
	vector <ll> tmp(205,0);
	for(int i=l;i<=r;i++)
		for(int j=t-h[i];j>=0;j--)
			tmp[j+h[i]]=max(tmp[j+h[i]],tmp[j]+w[i]);
	return tmp[t];
}
ll res=0;
void solve()
{
	int L=1,R=0;
	ll tmp[205],cp[205];
	for(int i=1,j=1;i<=num;i++)
	{
		R=en[i];
		L=en[i]+1;
		memset(tmp,0,sizeof tmp);memset(cp,0,sizeof cp);
		while(i==bl[q[j].l])
		{
			if(q[j].r-q[j].l<=sq)
			{
				// cout<<"********"<<endl;
				// cout<<q[j].l<<" "<<q[j].r<<endl;
				ans[q[j].id]=force(q[j].l,q[j].r,q[j].t);
				j++;
				continue;
			}
			L=en[i]+1;
			while(R<q[j].r)
			{
				// cout<<"****"<<endl;
				R++;
				for(int j=200-h[R];j>=0;j--)tmp[j+h[R]]=max(tmp[j+h[R]],tmp[j]+w[R]);
			}		
			memset(cp,0,sizeof cp);
			while(L>q[j].l)
			{
				L--;
				for(int t=200-h[L];t>=0;t--)cp[t+h[L]]=max(cp[t+h[L]],cp[t]+w[L]);
			}

			for(int t=q[j].t;t>=0;t--)
				ans[q[j].id]=max(ans[q[j].id],tmp[t]+cp[q[j].t-t]);
			// cout<<"***"<<q[j].l<<" "<<q[j].r<<endl;
			// cout<<q[j].id<<" "<<ans[q[j].id]<<" "<<bl[q[j].l]<<" "<<q[j].l<<" "<<q[j].r<<endl;
			// cout<<"CORRECT"<<force(q[j].l,q[j].r,q[j].t)<<endl;
			j++;
		}
	}
}
int main()
{
	speed();
	// freopen("3.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	
	cin>>n>>m;
	sq=sqrt(n);num=n/sq;
	// cout<<"*****"<<n<<" "<<m<<endl;
	for(int i=1;i<=n;i++)cin>>h[i];
	for(int i=1;i<=n;i++)cin>>w[i];
	for(int i=1;i<=m;i++)
	{
		cin>>q[i].l>>q[i].r>>q[i].t;
		q[i].id=i;
	}
	for(int i=1;i<=num;i++)
	{
		st[i]=en[i-1]+1;en[i]=st[i]+sq-1;
		// cout<<st[i]<<" "<<en[i]<<endl;
	}
	for(int i=1;i<=n;i++)bl[i]=(i-1)/sq+1;
	if(en[num]<n)
	{
		num++;st[num]=en[num-1]+1;
		en[num]=n;
	}
	sort(q+1,q+1+m);
	// init();
	solve();
	for(int i=1;i<=m;i++)
	{
		cout<<ans[i]<<endl;
	}
	return 0;
}

貓樹分治做法

點選檢視程式碼

#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
// #define int long long
const int N = 4E4+5,M=2e5+5;
int h[N],w[N],n,m;ll ans[M],sq,num;
int p[M],s[M],tn,tmid;
int f[N][205];
struct qu
{
	int l,r,t,id;
}q[M];
void solve(int l,int r,int tl,int tr)
{
	// cout<<l<<" "<<r<<endl;
	if(tl>tr)return;
	if(l==r)return;
	int mid=(l+r)>>1;tmid=tl-1;
	for(int i=0;i<=200;i++)f[mid][i]=0;
	for(int i=mid+1;i<=r;i++)
	{
		for(int j=0;j<h[i];j++)f[i][j]=f[i-1][j];
		for(int j=h[i];j<=200;j++)
			f[i][j]=max(f[i-1][j],f[i-1][j-h[i]]+w[i]);
	}

	for(int i=h[mid];i<=200;i++)f[mid][i]=w[mid];
	for(int i=mid-1;i>=l;i--)
	{
		for(int j=0;j<h[i];j++)f[i][j]=f[i+1][j];
		for(int j=h[i];j<=200;j++)
			f[i][j]=max(f[i+1][j],f[i+1][j-h[i]]+w[i]);
	}

	tn=0;
	int u=0;
	for(int i=tl;i<=tr;i++)
	{
		u=p[i];
		if(q[u].r<=mid)p[++tmid]=u;
		else if(q[u].l>mid)s[++tn]=u;	
		else
		{
			ll res=0;
			for(int i=0;i<=q[u].t;i++)
				res=max<ll>(res,f[q[u].l][i]+f[q[u].r][q[u].t-i]);
			ans[u]=res;
		}
	}
	for(int i=1;i<=tn;i++)p[tmid+i]=s[i];
	tr=tn+tmid;
	solve(l,mid,tl,tmid);
	solve(mid+1,r,tmid+1,tr);
}
int main()
{
	speed();
	// freopen("3.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	
	cin>>n>>m;
	// cout<<"*****"<<n<<" "<<m<<endl;
	for(int i=1;i<=n;i++)cin>>h[i];
	for(int i=1;i<=n;i++)cin>>w[i];
	for(int i=1;i<=m;i++)
	{
		cin>>q[i].l>>q[i].r>>q[i].t;
		if(q[i].l==q[i].r)
		{
			if(q[i].t>=h[q[i].l])ans[i]=w[q[i].l];
		}else p[++tn]=i;
	}
	solve(1,n,1,tn);
	for(int i=1;i<=m;i++)
	{
		cout<<ans[i]<<endl;
	}
	return 0;
}

image

暴力程式碼
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
using namespace std;
const int  N =305,mod=998244353;
const ull B=233;
ll n,m,a[N];
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
struct qu
{
	int l,r;
}q[50000+5];
set<ull> s;
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>q[i].l>>q[i].r;
	}
	for(int i=1;i<=n;i++)a[i]=i;
	if(n>10)
	{
		cout<<qpow(2,m)<<endl;
		return 0;
	}
	do
	{
		ull tmp=0;
		for(int i=1;i<=m;i++)
		{
			int mx=0,maxnn=0;
			for(int j=q[i].l;j<=q[i].r;j++)
			{
				if(maxnn<a[j])
				{
					maxnn=a[j];
					mx=j;
				}
			}
			tmp=tmp*B+mx;
		}
		// unique(chk.begin(),chk.end());
		// sort(chk.)
		s.insert(tmp);
		
	}while(next_permutation(a+1,a+1+n));
	cout<<s.size()%mod;
	return 0;
}