颓了好几天的blog 应该写写了 毕竟有些题目仍是很不错的关键是dp 每次都推不出来 果真仍是我太菜了.ios
今天 考的是牛客的比赛 质量还行 不过时望的分220 实际得分180/cy 好多神仙AK 各类崩溃 dp推不出来 图论不会写 很自闭反正... T1 100 T2 40 T3 40c++
LINK:简单博弈问题数组
这道题就颇有意思了 典型的博弈问题 多个局面 考虑有向图游戏的和求SG函数 对于一个局面不一样的石子个数不一样 没有任何关系 仔细分析每个局面。网络
对于1 必胜局 对于2 必败局 对于3 必败局...好像没什么规律 考虑偶数和奇数分开来看 偶数 咱们后手是始终贴着先手下 能够发现只有先手不能走 因此偶数局面先手必败。ide
考虑大于1 的奇数局面 咱们后手 的第一步下在先手第一步的棋子旁边的旁边 此时先手有两个位置不能下 然后手只有一个位置不能下 以后继续贴着先手下 能够发现仍是先手败了 尽管能多下一个位置可是 被第一步反了一个位置造成相似于偶数的局面此时仍是先手先下。函数
因此获得SG函数 除了1这个局面 其他全部局面都是0 而后求有向图游戏的和便可。测试
//单个局面偶数必败 //以为单个局面除了1 剩下也是必败 直接异或好了 //#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define pii pair<ll,ll> #define mk make_pair using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } int T; int n,ans; int main() { T=read(); while(T--) { ans=0; n=read(); for(int i=1;i<=n;++i) { int x=read(); if(x==1)ans^=1; } if(ans)puts("rabbit"); else puts("hamster"); } return 0; }
两个mingw 一遍补模拟赛的题目一遍写其余题目毕竟考了就要补。优化
LINK:树形dp问题 spa
这道题仍是很不错的引出了树上dp经常使用的两个方法 换根dp 和 up and down 都挺常见的 不过我最经常使用的是换根 这道题我决定两种方法都写一下。3d
首先是第一问 求以任意一个点为根的 深度不超过k的儿子的个数. 先考虑第一种比较不熟悉的方法 up and down。
1 预处理 设 f[i][j] 表示以i为根的子树内小于k的深度的点的个数。w[i][j]表示i向上j层的点数
2 预处理 设g[i][j]表示以i为根的子树内小于k的深度点的乘积不包括其自己 c[i][j]表示向上的不超过j的点的乘积 不包括其自己。
处理好以后 发现答案就有了/cy 转移挺难写的 一道很是有实际意义的题目。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define INF 1000000000 #define ll long long #define db double #define pb push_back #define un unsigned #define mod 1000000007 #define ull unsigned long long using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=100010; int n,k,len; int f[MAXN][11];//f[i][j]表示以i为根的子树内小于等于j的点的个数. int w[MAXN][11];//w[i][j]表示从i向上深度为不超过j的点的个数 ll g[MAXN][11];//g[i][j]表示以i为根的子树内部深度小于等于j的点的乘积 不包含其自己 ll c[MAXN][11];//c[i][j]表示从i向上深度不超过j的点的乘积 不包含其自己 int lin[MAXN],nex[MAXN<<1],ver[MAXN<<1]; inline void add(int x,int y) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; } inline ll fast_pow(ll b,ll p) { ll ans=1; while(p) { if(p&1)ans=ans*b%mod; b=b*b%mod; p=p>>1; } return ans; } inline void dfs(int x,int father) { for(int i=0;i<=k;++i)f[x][i]=1; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; dfs(tn,x); for(int j=1;j<=k;++j)f[x][j]+=f[tn][j-1]; } } inline void dfs1(int x,int father) { for(int i=0;i<=k;++i)g[x][i]=1; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; dfs1(tn,x); for(int j=1;j<=k;++j)g[x][j]=g[x][j]*g[tn][j-1]%mod*f[tn][j-1]%mod; } } inline void dp(int x,int father) { for(int i=0;i<=k;++i)w[x][i]+=1; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; for(int j=1;j<=k;++j) { w[tn][j]+=w[x][j-1]; if(j>=2)w[tn][j]+=f[x][j-1]-1-f[tn][j-2]; } dp(tn,x); } } inline void dp1(int x,int father) { for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; for(int j=1;j<=k;++j) { c[tn][j]=c[tn][j]*c[x][j-1]%mod*g[x][j-1]%mod; if(j>=2) { c[tn][j]=c[tn][j]*(w[x][j-1]+f[x][j-1]-1-f[tn][j-2])%mod; c[tn][j]=c[tn][j]*fast_pow(g[tn][j-2],mod-2)%mod; c[tn][j]=c[tn][j]*fast_pow(f[tn][j-2],mod-2)%mod; } } dp1(tn,x); } } int main() { //freopen("1.in","r",stdin); n=read();k=read(); for(int i=1;i<n;++i) { int x,y; x=read();y=read(); add(x,y);add(y,x); } dfs(1,0); //求出以某个点为根的深度不超过j的点的个数. dp(1,0); //for(int i=1;i<=n;++i)printf("%d ",f[i][k]); //for(int i=1;i<=n;++i)printf("%d ",w[i][k]); for(int i=1;i<=n;++i)printf("%d ",f[i][k]+w[i][k]-1); puts(""); dfs1(1,0); //求出以某个点位根的深度不超过j的点的个数. for(int i=1;i<=n;++i)for(int j=0;j<=k;++j)c[i][j]=1; dp1(1,0); //for(int i=1;i<=n;++i)printf("%d ",g[i][k]); //for(int i=1;i<=n;++i)printf("%d ",c[i][k]); for(int i=1;i<=n;++i)printf("%lld ",c[i][k]*g[i][k]%mod*(f[i][k]+w[i][k]-1)%mod); return 0; }
发现遇到这类问题很是的胆怯 好像是不敢去思考 这类问题我想应该不难只是本身懒的想这种私下跟实际上是不可取的qwq。
首先 每张牌有两种选择 而后显然是一个二分图的问题 没多想直接暴力网络流了 加上测试点4的前缀和处理能够获得40分。
考虑满分作法 咱们发现 一个事情 其实也能够选择匈牙利直接二分图的最大匹配。复杂度qn^2 咱们能够顺势优化这个东西。
对于一个左端点 必定 有一个与之对应能表示出来的最大的右端点 而后左端点移动的同时右端点也同时移动 咱们预处理这个东西 而后O(1) 回答询问便可。
复杂度n^2+Q 实测可过 缘由 跑不满的缘故 咱们由此想到用网络流优化这个过程复杂度能够达到nsqrt(n);
可实际上 网络流更换匹配的过程很是的复杂还须要修改一条流这个是很难作到的 因此基本上很难优化。固然直接匈牙利修改好修改 并且必定跑不满因此梦想匈牙利就过去了。
考虑真正的满分作法。这其实是一个图论的问题 考虑每一张牌把两个花色连了起来 咱们抽象成 几个连通块。
能够发现若是联通块是一颗树那么这棵树 这几个节点都不能被同时体现。考虑一下询问 一个询问的不合法当且仅当其包含了一棵完整的树。
这样的话 如何判断一条线段包含了 这样的一棵树 显然 对于一棵树尽管多是不连续的 可是 判断包含关系只须要 找到树的编号的最大值及最小值这个线段包含树的两端便可。
那么 就是 一个经典问题了 线段之间的覆盖问题。 显然 咱们离线一下利用树状数组便可。复杂度mlogn.
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define pii pair<ll,ll> #define mk make_pair #define mod 1000000007 using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=100010; int n,m,len,minn,maxx; int q[MAXN],f[MAXN],vis[MAXN],c[MAXN],ans[MAXN],top; int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1]; inline void add(int x,int y) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; } inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);} inline void dfs(int x,int father) { maxx=max(maxx,x); minn=min(minn,x); for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(tn==father)continue; dfs(tn,x); } } struct wy { int x,y; int id; int friend operator <(wy a,wy b) { return a.x<b.x; } }t[MAXN],w[MAXN]; inline void add1(int x,int y) { while(x<=n) { c[x]+=y; x+=x&(-x); } return; } inline int ask(int x) { int cnt=0; while(x) { cnt+=c[x]; x-=x&(-x); } return cnt; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;++i)f[i]=i; for(int i=1;i<=m;++i) { int x,y; x=read();y=read(); add(x,y);add(y,x); int xx=getfather(x); int yy=getfather(y); if(xx==yy)vis[xx]=1; f[xx]=yy; } for(int i=1;i<=n;++i) { int x=getfather(i); if(vis[x])continue; q[++top]=i; vis[x]=1; } //for(int i=1;i<=top;++i)printf("%d\n",q[i]); for(int i=1;i<=top;++i) { minn=INF,maxx=0; dfs(q[i],0); w[i]=(wy){minn,maxx}; add1(maxx,1); } m=read(); for(int i=1;i<=m;++i) { int x,y; x=read();y=read(); t[i]=(wy){x,y,i}; } sort(t+1,t+1+m); sort(w+1,w+1+top); int flag=1; for(int i=1;i<=m;++i) { while(flag<=top&&w[flag].x<t[i].x) { add1(w[flag].y,-1); ++flag; } ans[t[i].id]=ask(t[i].y); } for(int i=1;i<=m;++i)puts(ans[i]?"No":"Yes"); return 0; }