A.3132
给一个有向图,问能否从任意点出发都能进入一个环中。
深搜。
#include<bits/stdc++.h> using namespace std; const int N=55; vector<int>G[N]; bool vis[N]; int f; void dfs(int u) { if(f)return; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!vis[v]) { vis[v]=1; dfs(v); } else { f=1; return; } } } int main() { int n,m; char s1[5],s2[5]; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++)G[i].clear(); for(int i=0;i<m;i++) { int u,v; scanf("%s%s",s1,s2); G[s1[0]-'A'+1].push_back(s2[0]-'A'+1); } for(int i=1;i<=n;i++) { f=0; memset(vis,0,sizeof vis); dfs(i); if(!f)break; } printf("%s\n",f?"YES":"NO"); } return 0; }
B.4971
给一颗树,n个起点,问到1的路径权值和,一个点的权值只算一次。
深搜。
#include<bits/stdc++.h> using namespace std; const int N=1005; vector<int>G[N]; bool vis[N]; int father[N],be[N],val[N]; void dfs(int u,int fa) { father[u]=fa; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(v==fa)continue; dfs(v,u); } } int main() { int n,m,ca=1; while(scanf("%d%d",&n,&m)!=EOF) { memset(vis,0,sizeof vis); for(int i=1;i<=n;i++)G[i].clear(); for(int i=1;i<=m;i++) scanf("%d",&be[i]); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,0); int sum=0; for(int i=1;i<=m;i++) { int f=be[i]; if(!vis[f])vis[f]=1,sum+=val[f]; while(f) { f=father[f]; if(!vis[f])vis[f]=1,sum+=val[f]; } } printf("Case #%d: %d\n",ca++,sum); } return 0; }
C.4976
给一个二进制串,其中有一堆未知数,问有几种填法使得十进制数中含6。
深搜。
#include <bits/stdc++.h> using namespace std; #define ll long long int p[1005]; string s; int l; int num=0; void dfs(int pos,ll ans) { if(pos==l) { while(ans) { if(ans%10==6) { num++; break; } ans=ans/10; } return; } if(s[pos]=='0') dfs(pos+1,ans*2); else if(s[pos]=='1') dfs(pos+1,ans*2+1); else { dfs(pos+1,ans*2); dfs(pos+1,ans*2+1); } } int main() { while(cin>>s) { num=0; l=s.size(); dfs(0,0); cout<<num<<endl; } return 0; }
D.4546
M段区间每段区间只能有一张假票,问最多能有几张假票,若不合法输出-1。
不会(待补)
E.4587
有两颗苹果树,贝西初始站在1下,每分钟掉下1个苹果,贝西最多移动W次,问T分钟贝西最多能接到多少苹果。
dp[t][w][3]表示在t分钟移动w次现在站在苹果树几下。
#include<bits/stdc++.h> using namespace std; int dp[1005][35][2]; int main() { for(int i=0;i<1005;i++) for(int j=0;j<35;j++) dp[i][j][0]=dp[i][j][1]=-1000000000; int T,W; scanf("%d%d",&T,&W); for(int i=0;i<T;i++) dp[i][W][0]=0; for(int i=0,x;i<T;i++) { scanf("%d",&x); if(!i) { if(x==1) dp[i][W][0]=1; else if(x==2) dp[i][W-1][1]=1; } else { for(int j=W;j>=0;j--) { if(x==1) { dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]+1); if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]+1); dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]); if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]); } else if(x==2) { dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+1); if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]+1); dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]); if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]); } } } } int ans=0; for(int i=0;i<=W;i++) ans=max(ans,max(dp[T-1][i][0],dp[T-1][i][1])); printf("%d\n",ans); return 0; }
F.4596
n个盒子按1-n编号,m次操作,1XY把x放在y左边,2XY把x放在y右边,3XYxy互换位置,4翻转,问操作完所有奇数位置的盒子编号之和。
双向链表,L[i]=i-1,R[i]=i+1,着实有点难写。
#include<stdio.h> #include<string.h> #define maxn 100000+5 typedef long long LL; int pre[maxn],next[maxn],n,m; int main() { int T=0; while(~scanf("%d%d",&n,&m)) { int tot=0; for(int i=1;i<=n;++i) { pre[i]=i-1; next[i]=i+1; } next[n]=0; // int op,x,y; for(int i=1;i<=m;++i) { scanf("%d",&op); if(op!=4) scanf("%d%d",&x,&y); else { ++tot; continue; } if((tot&1)&&op<3) op=3-op; if(op==1) { if(pre[y]==x) continue; next[pre[x]]=next[x]; pre[next[x]]=pre[x]; next[pre[y]]=x; pre[x]=pre[y]; next[x]=y; pre[y]=x; } else if(op==2) { if(next[y]==x) continue; next[pre[x]]=next[x]; pre[next[x]]=pre[x]; pre[next[y]]=x; next[x]=next[y]; pre[x]=y; next[y]=x; } else if(op==3) { if(next[x]==y) { int temp1=pre[x],temp2=next[y]; next[temp1]=y; pre[y]=temp1; pre[temp2]=x; next[x]=temp2; next[y]=x; pre[x]=y; } else if(next[y]==x) { int temp1=pre[y],temp2=next[x]; next[temp1]=x; pre[x]=temp1; pre[temp2]=y; next[y]=temp2; next[x]=y; pre[y]=x; } else { int temp1=next[y],temp2=pre[y]; next[pre[x]]=y; pre[next[x]]=y; next[pre[y]]=x; pre[next[y]]=x; next[y]=next[x]; pre[y]=pre[x]; next[x]=temp1; pre[x]=temp2; } } } int *st,*ed; if(tot&1) { st=next; ed=pre; } else { st=pre; ed=next; } LL ans=0; for(int i=1;i<=n;++i) { if(!st[i])//寻找开头 { for(int j=1; i ;i=ed[i],++j)//判断结尾,i=0也就是末尾的时候循环结束 if(j&1) ans+=i; break; } } printf("Case %d: %lld\n",++T,ans); } return 0; }
G.5066
n个点m条有向边,问从1出发最多经过几个点再回到1。
targin求含有1的强连通集合。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int low[N],dfn[N],Stack[N],tot,cnt; bool instack[N]; vector<int>G[N]; void tarjan(int u) { int v; dfn[u]=low[u]=++tot; Stack[++cnt]=u; instack[u]=true; for(int i=0;i<G[u].size();i++) { v=G[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { int sz=0; while(v=Stack[cnt--]) { instack[v]=false; sz++; if(u==v)break; } if(u==1)printf("%d\n",sz); } } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } tarjan(1); return 0; }
H.5129
题意不明
不会(待补)
I.5166
n个点构造一个哈夫曼树。
贪心每次取两个最小的。
#include<bits/stdc++.h> using namespace std; int main() { priority_queue< int,vector<int>,greater<int> >q; int n; cin>>n; for(int i=1;i<=n;i++) { int a; cin>>a; q.push(a); } int sum=0; while(q.size()>1) { int a=q.top();q.pop(); int b=q.top();q.pop(); sum+=a+b; q.push(a+b); } cout<<sum; return 0; }
J.4992
n次移动,(0,0)朝北出发,每次走ai步,走完后右转,如果路径冲突,输出移动了几次,否则输出OK。
首先几何知识判断两条线段是否相交或重叠。
通过观察发现当前这条线段最多和前面8条线段存在冲突。
#include <cstdio> #include <algorithm> using namespace std; const int MAX = 1000007, dx[] = { 0, 1, 0, -1 }, dy[] = { 1, 0, -1, 0 }; int N, a[MAX]; struct Point { int x, y; Point(int _x = 0, int _y = 0) : x(_x), y(_y) {} } points[MAX]; // true, if intervals [a,b] and [c,d] have non-empty intersection bool overlap(int a, int b, int c, int d) { if (a > b) swap(a, b); if (c > d) swap(c, d); return !(b < c || d < a); } // true if line segments [a1,a2] and [b1,b2] have non-empty intersection bool intersect(Point a1, Point a2, Point b1, Point b2) { bool is_vertical_a = (a1.x == a2.x), is_vertical_b = (b1.x == b2.x); if (is_vertical_a && is_vertical_b) return a1.x == b1.x && overlap(a1.y, a2.y, b1.y, b2.y); if (!is_vertical_a && !is_vertical_b) return a1.y == b1.y && overlap(a1.x, a2.x, b1.x, b2.x); // make a horizontal and b vertical if (is_vertical_a) { swap(a1, b1); swap(a2, b2); } return !( max(a1.x, a2.x) < b1.x || min(a1.x, a2.x) > b1.x || max(b1.y, b2.y) < a1.y || min(b1.y, b2.y) > a1.y); } int solve() { int x = 0, y = 0; for (int i = 0; i < N; ++i) { x += dx[i & 3] * a[i]; y += dy[i & 3] * a[i]; points[i + 1].x = x; points[i + 1].y = y; for (int j = max(0, i - 8); j < i - 2; ++j) if (intersect(points[j], points[j + 1], points[i], points[i + 1])) return i; } return -1; } int main() { while (scanf("%d", &N) == 1) { for (int i = 0; i < N; ++i) scanf("%d", a + i); int result = solve(); if (result == -1) printf("OK\n"); else printf("%d\n", result); } return 0; }
K.4541
n个数,求插入个数最少的整数,使其成为一个回文数列。
dp,答案是n-最长回文子序列的长度。
设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。
状态转移方程如下:
当i>j时,f(i,j)=0。
当i=j时,f(i,j)=1。
当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。
当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。
由于f(i,j)依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从s.length()-1到0。
最后,s的最长回文子序列长度为f(0, s.length()-1)。
可以发现计算第i行时只用到了第i+1行,所以可以滚动数组减少内存使用。
#include<bits/stdc++.h> using namespace std; const int N=10005; int a[N],n,dp[2][N]; int main() { int T; scanf("%d",&T); while(T--) { memset(dp,0,sizeof dp); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int cnt=0; for(int i=n;i>=1;i--) { cnt^=1; memset(dp[cnt],0,sizeof dp[cnt]); dp[cnt][i]=1; for(int j=i+1;j<=n;j++) { if(a[i]==a[j]) dp[cnt][j]=dp[cnt^1][j-1]+2; else dp[cnt][j]=max(dp[cnt][j-1],dp[cnt^1][j]); } } printf("%d\n",n-dp[cnt][n]); } return 0; }
L.4561
n个人,1号为Sheldon,已知其余n-1个人投给了f[i]要买通需要花费c[i],1号需要投给1个人。最后1想要花最少的钱使得自己的票数>其他所有人的票数,求最少的钱。
贪心+讨论
这里每个人票数为p[i]。
1投给目前票数最少的人(好好思考思考),然后考虑1需要x票能赢,那么其余人i只要p[i]>=x就需要买通p[i]-x+1个人,肯定买最便宜的,最后如果1还差k票,那么把所有没买通的人按c[i]排序再取k个最小。
#include<bits/stdc++.h> using namespace std; vector<int>vec[105]; int f[105],c[105],t,a; int main() { cin>>t; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++)vec[i].clear(); for(int i=2;i<=n;i++)cin>>f[i]; for(int i=2;i<=n;i++)cin>>c[i]; for(int i=2;i<=n;i++)vec[f[i]].push_back(c[i]); for(int i=1;i<=n;i++)sort(vec[i].begin(),vec[i].end()); int M_P=1e9,M_POS=1; for(int i=2;i<=n;i++) { if((int)vec[i].size()<M_P) { M_P=(int)vec[i].size(); M_POS=i; } } int sl=0; for(int i=1;i<=n;i++)if((int)vec[i].size()==M_P)sl++; if(sl==n) { int Minn=1e9,Minnp=1; for(int i=2;i<=n;i++)if((int)vec[i].size()>0&&vec[i][0]<Minn)Minn=vec[i][0],Minnp=i; vec[Minnp].push_back(0x3f3f3f3f); } else vec[M_POS].push_back(0x3f3f3f3f); int Min=1e9; for(int i=(int)vec[1].size();i<n;i++) { vector<int>prem[105],prr; int NEED=i-(int)vec[1].size(); for(int j=2;j<=n;j++)prem[j]=vec[j]; int sum=0; for(int j=2;j<=n;j++) { if((int)prem[j].size()>=i) { int need=(int)prem[j].size()-i+1; NEED-=need; if(NEED<0)goto e; for(int k=0;k<need;k++)sum+=prem[j][k]; for(int k=need;k<(int)prem[j].size();k++)prr.push_back(prem[j][k]); } else { for(int k=0;k<(int)prem[j].size();k++) prr.push_back(prem[j][k]); } } if(NEED>0) { sort(prr.begin(),prr.end()); for(int j=0;j<NEED;j++)sum+=prr[j]; } Min=min(Min,sum); e:; } cout<<Min<<endl; } return 0; }
M.2337
已知Dick12岁,janepuff和spot相差s岁,yertle和puff相差p岁,yertle和spot相差y岁,Spot, Puff, Yertle和等于Dick,jane和,求Spot, Puff, Yertle的岁数。
那么由确定关系,设yertle为x岁,那么spot为x + y, puff为x + p然后与s进行比较。
#include<bits/stdc++.h> using namespace std; int main() { int n,s,p,y,t; cin>>n; while(n--) { cin>>s>>p>>y>>t; int sum=12+t; int temp=sum-y-p; int x=temp/3; if(temp%3==0) cout<<x+y<<" "<<x+p<<" "<<x<<endl; else if(temp%3==1) { if(s+p==y) cout<<x+y+1<<" "<<x+p<<" "<<x<<endl; else cout<<x+y<<" "<<x+p+1<<" "<<x<<endl; } else cout<<x+y+1<<" "<<x+p+1<<" "<<x<<endl; } return 0; }