T1
本來是道狀壓簽到題,看成博弈論了,其實是不對的,為什麼不對,建圖時是存在環的情況的,所以不能建一棵樹後跑\(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
構造題,首先我們可以把\(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
回滾莫隊能過
細節,用\(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;
}
暴力程式碼
#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;
}