屯题2
1.BZOJ1026
数位DP裸题,纯属为了回忆一下而做的
代码如下:
#include<bits/stdc++.h> #define int long long #define N 55 using namespace std; int L,R,a[N],dp[N][N]; int dfs(int pos,int last,bool limit,bool lead){ if (pos==0) return 1; if (limit&&lead&&dp[pos][last]) return dp[pos][last]; int ans=0,up; if (limit) up=9;else up=a[pos]; for (int i=0;i<=up;i++){ if (abs(i-last)<2&&lead) continue; ans=ans+dfs(pos-1,i,(limit|(i!=a[pos])),(lead|(i!=0))); } if (limit&&lead) dp[pos][last]=ans;return ans; } inline int solve(int x){ int xb=x;int tot=0; while (xb){ a[++tot]=xb%10; xb/=10; } memset(dp,0,sizeof(dp)); return dfs(tot,0,0,0); } signed main(){ scanf("%lld%lld",&L,&R); printf("%lld\n",solve(R)-solve(L-1)); return 0; }
2.BZOJ4484
个人感觉还是有点难想到拓扑序的
跑出拓扑序,然后倒着跑
跑的时候用bitset维护连通性
代码如下:
#include<bits/stdc++.h> #define pi pair<int,int> #define mk make_pair #define N 30005 using namespace std; int n,m,x,y,kk,ans,left1,right1,q[N*10],ru[N*10],head[N*10],dis[N*10]; bitset<N>bit[N]; struct Edge{int nxt,to;}e[N*10]; inline void link(int x,int y){e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;} inline void topsort(){ left1=1,right1=0; for (int i=1;i<=n;i++) if (!ru[i]) q[++right1]=i; while (left1<=right1){ int u=q[left1++]; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; ru[v]--; if (!ru[v]) q[++right1]=v; } } } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); link(x,y);ru[y]++; } topsort();ans=0; for (int i=right1;i;i--){ int u=q[i]; for (int j=head[u];j;j=e[j].nxt){ int v=e[j].to; bit[u]|=bit[v]; } for (int j=head[u];j;j=e[j].nxt){ int v=e[j].to; if (bit[u][v]) ans++; bit[u][v]=1; } } printf("%d\n",ans); return 0; }
3.BZOJ4774
斯坦纳树入门题,通过这个我终于学会了斯坦纳数(现在才会,真是菜
在之前的博客中有很详细的解释
代码如下:
/*https://blog.csdn.net/wu_tongtong/article/details/78992913*/ #include<bits/stdc++.h> #define N 40005 using namespace std; int n,m,d,x,y,z,cnt,inf,kk,left1,right1,head[N],q[N*400],g[N],use[N],dp[N][1<<8]; struct Edge{int nxt,to,step;}e[N]; inline void link(int x,int y,int z){e[++kk].nxt=head[x];e[kk].to=y;e[kk].step=z;head[x]=kk;} inline void spfa(int S){ while (left1<=right1){ int u=q[left1++]; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (dp[v][S]>dp[u][S]+e[i].step){ dp[v][S]=dp[u][S]+e[i].step; q[++right1]=v; } } } } inline bool check(int S1){ for (int i=0;i<d;i++){ if (S1>>i&1) if (!(S1>>(d+i)&1)) return 0; } return 1; } int main(){ scanf("%d%d%d",&n,&m,&d); for (int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); link(x,y,z);link(y,x,z); } memset(g,127/3,sizeof(g)); memset(dp,127/3,sizeof(dp));inf=dp[0][0]; for (int i=1;i<=d;i++) use[++cnt]=i; for (int i=n;i>=n-d+1;i--) use[++cnt]=i; for (int i=1;i<=cnt;i++) dp[use[i]][1<<(i-1)]=0; for (int j=0;j<(1<<cnt);j++){ for (int i=1;i<=n;i++) for (int k=(j-1)&j;k;k=(k-1)&j) dp[i][j]=min(dp[i][j],dp[i][k]+dp[i][j^k]); left1=1;right1=0; for (int i=1;i<=n;i++) if (dp[i][j]<inf) q[++right1]=i; spfa(j);//g[j]=inf; for (int i=1;i<=n;i++) g[j]=min(g[j],dp[i][j]); } for (int i=0;i<(1<<cnt);i++) for (int j=(i-1)&i;j;j=(j-1)&i) if (check(j)&&check(i^j)) g[i]=min(g[i],g[j]+g[i^j]); if (g[(1<<cnt)-1]>=inf) puts("-1"); else printf("%d\n",g[(1<<cnt)-1]); return 0; }
4.codechef A humongous Query
这题真的高的不行,无法谈笑风生啊
考虑dp,我们发现这玩意可以倒退回去
所以枚举dp的值,然后倒退判断是否符合初始化即可
太高了
#include<bits/stdc++.h> #define inf 1000000000 #define N 50005 using namespace std; int T,X;char s[N]; int main(){ scanf("%d",&T); while (T--){ scanf("%s",s+1); scanf("%d",&X); int n=strlen(s+1); int ans=inf; for (int i=0;i<=X;i++){ int f0=X,f1=i; int tot=0;bool flag=1; for (int j=n;j>1;j--){ if (f1<0||f0<0){flag=false;break;} if (f0>=f1){ f0=f0-f1; if (s[j]!='0') tot++; } else { f1=f1-f0-1; if (s[j]!='1') tot++; } } f1=f1-f0-1; if (flag&&f1==0&&f0==0) ans=min(ans,tot); } if (ans==inf) puts("NO"); else puts("YES"),printf("%d\n",ans); } return 0; }