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;
}