11.5 两次考试
上午
题还是比较水的...
T1 attack
题意:
给一个有向图,Q次询问K个点,问从1到K个点的必经点 (没说是DAG,但数据是DAG...)、
支配树的裸题吗,但是不会支配树啊....
然后就求割点,桥,然后就懵逼了....
DAG上支配树直接增量构造就好了
有环的还不会...
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=100006; int first[N],ver[N<<1],nt[N<<1],e; void addb(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } struct FAN { int first[N],ver[N<<1],nt[N<<1],e; void clear() { e=0; mem(first,-1); } void addb(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } }h[2]; int n,m,Q,K; int maxk; int deg[N]; int fa[N],dep[N],st[N][21]; int LCA(int x,int y) { if(dep[x]<dep[y]) x^=y,y^=x,x^=y; int j; for(j=maxk;~j;--j) if(dep[x]-(1<<j)>=dep[y]) x=st[x][j]; if(x==y) return x; for(j=maxk;~j;--j) if(st[x][j]!=-1&&st[x][j]!=st[y][j]) x=st[x][j],y=st[y][j]; return fa[x]; } void match(int x,int y) { fa[x]=y; dep[x]=dep[y]+1; st[x][0]=y; int j; for(j=1;j<=maxk&&st[x][j-1]!=-1;++j) st[x][j]=st[st[x][j-1]][j-1]; } int dui[N<<2],he,en; void build() { while((1<<maxk)<=n) ++maxk; --maxk; mem(st,-1); fa[1]=-1; he=1; en=0; dui[++en]=1; int now,ve,las; rint i; while(en>=he) { now=dui[he++]; las=0; for(i=h[0].first[now];i!=-1;i=h[0].nt[i]) { ve=h[0].ver[i]; if(las) las=LCA(las,ve); else las=ve; } if(las) match(now,las); for(i=first[now];i!=-1;i=nt[i]) { --deg[ver[i]]; if(!deg[ver[i]]) dui[++en]=ver[i]; } } } void work() { rint i,j; int tin,las; for(i=1;i<=Q;++i) { read(K); las=0; for(j=1;j<=K;++j) { read(tin); if(las) las=LCA(las,tin); else las=tin; } printf("%d\n",dep[las]+1); } } int main(){ rint i; int tin1,tin2; mem(first,-1); h[1].clear(); h[0].clear(); read(n); read(m); read(Q); for(i=1;i<=m;++i) { read(tin1); read(tin2); ++deg[tin2]; addb(tin1,tin2); h[0].addb(tin2,tin1); } build(); work(); }
T2 reverse
大水题,模拟就行了
我用了双取模...
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int #define ull unsigned long long using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int P1=76543; const int P2=1000003; const int LEN=5006; int T; int lena,lenb; int la,ra,fa,lb,rb,fb; char A[LEN],B[LEN]; ull prea1[LEN],sufa1[LEN],prea2[LEN],sufa2[LEN]; ull preb1[LEN],sufb1[LEN],preb2[LEN],sufb2[LEN]; ull PP1[LEN],PP2[LEN]; void rota() { if(fa) { if(A[la]=='A') ++la; else ++la,fa^=1; } else { if(A[ra]=='A') --ra; else --ra,fa^=1; } --lena; } void rotb() { if(fb) { if(B[lb]=='A') ++lb; else ++lb,fb^=1; } else { if(B[rb]=='A') --rb; else --rb,fb^=1; } --lenb; } int check() { ull haa1,haa2,hab1,hab2; if(fa) { haa1=(sufa1[la]-sufa1[ra+1]*PP1[ra-la+1]); haa2=(sufa2[la]-sufa2[ra+1]*PP2[ra-la+1]); } else { haa1=(prea1[ra]-prea1[la-1]*PP1[ra-la+1]); haa2=(prea2[ra]-prea2[la-1]*PP2[ra-la+1]); } if(fb) { hab1=(sufb1[lb]-sufb1[rb+1]*PP1[rb-lb+1]); hab2=(sufb2[lb]-sufb2[rb+1]*PP2[rb-lb+1]); } else { hab1=(preb1[rb]-preb1[lb-1]*PP1[rb-lb+1]); hab2=(preb2[rb]-preb2[lb-1]*PP2[rb-lb+1]); } if(haa1==hab1&&haa2==hab2) return 1; return 0; } void prin() { rint i; if(fa) { for(i=ra;i>=la;--i) printf("%c",A[i]); } else { for(i=la;i<=ra;++i) printf("%c",A[i]); } printf("\n"); /*if(fb) { for(i=rb;i>=lb;--i) printf("%c",B[i]); } else { for(i=lb;i<=rb;++i) printf("%c",B[i]); } printf("\n");*/ } void work() { rint i; int len; fa=fb=0; la=lb=1; ra=lena; rb=lenb; for(i=lena;i;--i) A[i]=A[i-1]; A[0]=0; for(i=lenb;i;--i) B[i]=B[i-1]; B[0]=0; /*printf("\n"); for(i=1;i<=lena;++i) printf("%c",A[i]); printf("\n");*/ for(i=1;i<=lena;++i) prea1[i]=(prea1[i-1]+A[i])*P1, prea2[i]=(prea2[i-1]+A[i])*P2; for(i=1;i<=lenb;++i) preb1[i]=(preb1[i-1]+B[i])*P1, preb2[i]=(preb2[i-1]+B[i])*P2; for(i=lena;i;--i) sufa1[i]=(sufa1[i+1]+A[i])*P1, sufa2[i]=(sufa2[i+1]+A[i])*P2; for(i=lenb;i;--i) sufb1[i]=(sufb1[i+1]+B[i])*P1, sufb2[i]=(sufb2[i+1]+B[i])*P2; while(lena>lenb) rota(); while(lenb>lena) rotb(); //prin(); len=lena; for(i=len;i;--i) { if(check()) { prin(); return ; } rota(); rotb(); } puts("-1"); } int main(){ //freopen("T2.in","r",stdin); //freopen("reverse.in","r",stdin); //freopen("reverse.out","w",stdout); rint i; PP1[0]=PP2[0]=1; for(i=1;i<LEN;++i) PP1[i]=PP1[i-1]*P1, PP2[i]=PP2[i-1]*P2; read(T); while(T--) { mem(A,0); mem(B,0); mem(prea1,0); mem(prea2,0); mem(sufa1,0); mem(sufa2,0); mem(preb1,0); mem(preb2,0); mem(sufb1,0); mem(sufb2,0); scanf("%s%s",A,B); lena=strlen(A); lenb=strlen(B); work(); } }
T3 tree
原题
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define dd double #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=100006; int first[N],nt[N<<1],ver[N<<1],e; void addb(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,maxk; ll sumg[N],f[N],g[N]; int fa[N];//dep[N]; void dfs1(int x) { f[x]=1; int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { fa[ver[i]]=x; //dep[ver[i]]=dep[x]+1; dfs1(ver[i]); f[x]+=f[ver[i]]+1; } } void dfs2(int x) { if(fa[x]!=-1) sumg[x]=sumg[fa[x]]; sumg[x]+=g[x]; int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { if(fa[x]!=-1) g[ver[i]]=g[x]+1; g[ver[i]]+=(1+f[x]-(f[ver[i]]+1)-1); dfs2(ver[i]); } } int main(){ //freopen("T3.in","r",stdin); //freopen("T3.out","w",stdout); //freopen("tree.in","r",stdin); //freopen("tree.out","w",stdout); rint i; int tin1,tin2; mem(first,-1); read(n); for(i=1;i<n;++i) { read(tin1); read(tin2); addb(tin1,tin2); addb(tin2,tin1); } fa[1]=-1; dfs1(1); dfs2(1); for(i=1;i<=n;++i) printf("%lld.000\n",sumg[i]+1); }
下午
T1 入阵曲
$O(n^3)$枚举,打个时间戳
ans忘开long long了...30分
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> //#include <ctime> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=1000006; int n,m,mod; int sum[406][406]; int tim[N],timer,cnt[N]; ll ans; int main(){ //freopen("T1.in","r",stdin); //freopen("T1.out","w",stdout); //freopen("rally.in","r",stdin); //freopen("rally.out","w",stdout); rint i,j,l,r; rint tt; read(n); read(m); read(mod); for(i=1;i<=n;++i) for(j=1;j<=m;++j) { read(tt); sum[i][j]=(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+tt+mod)%mod; } for(l=1;l<=m;++l) for(r=l;r<=m;++r) { ++timer; tim[0]=timer; cnt[0]=1; for(i=1;i<=n;++i) { tt=(sum[i][r]-sum[i][l-1]+mod)%mod; if(tim[tt]==timer) ans+=cnt[tt],++cnt[tt]; else tim[tt]=timer,cnt[tt]=1; } } printf("%lld\n",ans); // printf("\n%d\n",clock()); }
T2 将军令
poi火药那个题的削弱版
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=100006; int first[N],ver[N<<1],nt[N<<1],e; void addb(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,K,op; int ans; int d[N],le[N],fa[N]; void dfs(int x) { d[x]=0; int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { fa[ver[i]]=x; dfs(ver[i]); if(d[ver[i]]!=-1&&d[x]<d[ver[i]]+1) d[x]=d[ver[i]]+1; if(le[ver[i]]!=-1&&le[x]<le[ver[i]]-1) le[x]=le[ver[i]]-1; } if(le[x]>=d[x]) d[x]=-1; if(d[x]==K) { d[x]=-1; ++ans; le[x]=K; } } int main(){ //freopen("T2.in","r",stdin); //freopen("general.in","r",stdin); //freopen("general.out","w",stdout); rint i; int tin1,tin2; mem(first,-1); read(n); read(K); read(op); for(i=1;i<n;++i) { read(tin1); read(tin2); addb(tin1,tin2); addb(tin2,tin1); } mem(le,-1); mem(d,-1); dfs(1); if(d[1]!=-1) ++ans; printf("%d\n",ans); }
T3 星空
考试打的傻dp骗了80 2333333
先说说考试的傻dp吧
用背包dp预处理出$g_len$表示len这么长都覆盖一次需要的最小次数 (也可以bfs求拉)
$f_i$ 表示前i个原先没亮的点都点亮,并且其他原先亮着的点也亮着 $f[8]$
转移:
找出连续的一段,枚举往左往右到哪,然后转移
找出下一段连续的一段,这两段同时被点亮,转移
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } int n,K,m; int len[106],pos[106]; int g[80006]; int f[106]; void work12() { rint i; int ans=0; if(len[m]==1) ans=K; else { if(m==2) { for(i=1;i<=K;) { if(pos[i]==pos[i+1]-1) ++ans,i+=2; else ++ans,++i; } } else { for(i=1;i<=K;i+=2) ans+=(pos[i+1]-pos[i]); } } printf("%d\n",ans); } void work200() { rint i,j,k; int l1,r1,l2,r2,tt; mem(g,30); g[0]=0; for(i=1;i<=m;++i) for(j=n;j>=len[i];--j) if(g[j]>g[j-len[i]]+1) g[j]=g[j-len[i]]+1; mem(f,30); f[0]=0; pos[K+1]=n+1; for(i=1;i<=K;++i) { l1=i; r1=l1+1; while(r1<=K&&pos[r1]==pos[r1-1]+1) ++r1; --r1; l2=r1+1; r2=l2+1; while(r2<=K&&pos[r2]==pos[r2-1]+1) ++r2; --r2; for(j=pos[l1];j>pos[l1-1];--j) for(k=pos[r1];k<pos[r1+1];++k) { tt=g[k-j+1]+g[pos[l1]-j]+g[k-pos[r1]]; if(f[r1]>f[l1-1]+tt) f[r1]=f[l1-1]+tt; } if(l2<=K) { tt=g[pos[r2]-pos[l1]+1]+g[pos[l2]-pos[r1]-1]; if(f[r2]>tt+f[l1-1]) f[r2]=tt+f[l1-1]; tt=g[pos[l2]-pos[l1]]+g[pos[r2]-pos[r1]]; if(f[r2]>tt+f[l1-1]) f[r2]=tt+f[l1-1]; } } if(f[K]>100000) f[K]=K+m; printf("%d\n",f[K]); } void work4e4() { rint i,j,k; int l1,r1,l2,r2,tt; mem(g,30); g[0]=0; for(i=1;i<=m;++i) for(j=n;j>=len[i];--j) if(g[j]>g[j-len[i]]+1) g[j]=g[j-len[i]]+1; mem(f,30); f[0]=0; pos[K+1]=n+1; int ci; for(i=1;i<=K;++i) { l1=i; r1=l1+1; while(r1<=K&&pos[r1]==pos[r1-1]+1) ++r1; --r1; l2=r1+1; r2=l2+1; while(r2<=K&&pos[r2]==pos[r2-1]+1) ++r2; --r2; ci=0; for(j=pos[l1];j>pos[l1-1];--j) { ++ci; if(ci>60) break; for(k=pos[r1];k<pos[r1+1];++k) { tt=g[k-j+1]+g[pos[l1]-j]+g[k-pos[r1]]; if(f[r1]>f[l1-1]+tt) f[r1]=f[l1-1]+tt; } } ci=0; for(k=pos[r1];k<pos[r1+1];++k) { ++ci; if(ci>60) break; for(j=pos[l1];j>pos[l1-1];--j) { tt=g[k-j+1]+g[pos[l1]-j]+g[k-pos[r1]]; if(f[r1]>f[l1-1]+tt) f[r1]=f[l1-1]+tt; } } if(l2<=K) { tt=g[pos[r2]-pos[l1]+1]+g[pos[l2]-pos[r1]-1]; if(f[r2]>tt+f[l1-1]) f[r2]=tt+f[l1-1]; tt=g[pos[l2]-pos[l1]]+g[pos[r2]-pos[r1]]; if(f[r2]>tt+f[l1-1]) f[r2]=tt+f[l1-1]; } } if(f[K]>100000) f[K]=K+m; printf("%d\n",f[K]); } int main(){ //freopen("T3.in","r",stdin); //freopen("starlit.in","r",stdin); //freopen("starlit.out","w",stdout); rint i; read(n); read(K); read(m); for(i=1;i<=K;++i) read(pos[i]); sort(pos+1,pos+1+K); for(i=1;i<=m;++i) read(len[i]); sort(len+1,len+1+m); if(len[m]<=2) work12(); else if(n<=200) work200(); else work4e4(); }
正解
设$A_i$表示原序列,规定1是灭,0是亮
$B_i$是一个差分数组,$B_i=A_{i} ^ A_{i+1}$
问题转化成 不超过$2*K$个1,两两配对,问最小花费和
那么bfs预处理出来从一个1到另一个1的最小步数
然后状压就行了
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } int n,K,m,maxp; int len[106]; int t[106],con; int A[40006],g[40006]; int dis[36][36]; int dui[300006],he,en; void get(int pp) { mem(g,30); g[pp]=0; he=1; en=0; dui[++en]=pp; int i,now; while(en>=he) { now=dui[he++]; for(i=1;i<=m;++i) { if(now-len[i]>=0&&g[now-len[i]]>g[now]+1) { g[now-len[i]]=g[now]+1; dui[++en]=now-len[i]; } if(now+len[i]<=n&&g[now+len[i]]>g[now]+1) { g[now+len[i]]=g[now]+1; dui[++en]=now+len[i]; } } } } void bfs() { rint i,j; for(i=1;i<=con;++i) { get(t[i]); for(j=1;j<=con;++j) dis[i][j]=g[t[j]]; } } int f[(1<<16)+100]; int dp() { maxp=(1<<con)-1; mem(f,30); f[maxp]=0; rint i,j,k; for(i=maxp;~i;--i) for(j=1;j<=con;++j) for(k=j+1;k<=con;++k) if( ((1<<(j-1))&i) && ((1<<(k-1))&i) && f[i^(1<<(j-1))^(1<<(k-1))]>f[i]+dis[j][k] ) f[i^(1<<(j-1))^(1<<(k-1))]=f[i]+dis[j][k]; return f[0]; } int main(){ //freopen("T3.in","r",stdin); rint i; int tin; read(n); read(K); read(m); for(i=1;i<=K;++i) read(tin),A[tin]=1; for(i=1;i<=m;++i) read(len[i]); for(i=0;i<=n;++i) if( A[i]^A[i+1] ) t[++con]=i; bfs(); printf("%d\n",dp()); }