Codeforces Round #595 (Div. 3)
B
题意:表示第i个人会将一天后把书递给a【i】人,如【3,1,2】,第一个人会递给第三个人,第二个人会递给第一个人,第三个人得给第二个人。问每个人第一开始都拿着自己的东西,之后第一次拿回自己的书是什么时候。我们发现会形成一个环,环里的每个成员就确定了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; int n,m,T,a[N]; int p[N], ans[N]; int solve(int x) { int len = 0; int tmp = x; do { tmp = p[tmp]; len++; } while (tmp != x); do { ans[tmp] = len; tmp = p[tmp]; } while (tmp != x); return len; } int main() { int q; cin >> q; while (q--) { int n; cin>>n; for (int i = 1; i <= n; i++) { ans[i] = 0; } for (int i = 1; i <= n; i++) cin>>p[i]; for (int i = 1; i <= n; i++) { if (!ans[i]) { solve(i); } } for (int i = 1; i <= n; i++) { printf("%d%c", ans[i], " \n"[i==n]); } } return 0; }
C
你需要找到一个数比n大,这个数的要求就是它是由不同的3的幂次组成(每个只能一个);
解析:先将n化作三进制,如129就会变成11210,由于第三位出现2,即两个相同的,那我们可以把一直把2变为1,前面一位++,要不断进行把2给划掉;然后原来的2后面全变为0,就是11210变为100000。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; ll n,m,T,a[N],tmp; ll p[N], ans[N],num[N]; int solve(int x) { tmp=0; for(int i=38;i>=0;i--){ a[i]=n/num[i]; n%=num[i]; } for(int i=38;i>=0;i--){ if(a[i]==2){ tmp=i; break; } } for(int i=0;i<tmp;i++) a[i]=0; for(int i=tmp;i<=38;i++){ if(a[i]>=2){ a[i]=0; a[i+1]++; } } ll ans=0; for(int i=0;i<=38;i++){ if(a[i])ans+=num[i]; } printf("%lld\n",ans); } int main() { num[0]=1; for(int i=1;i<=38;i++) num[i]=num[i-1]*3; cin>>T; while(T--){ cin>>n; solve(n); } }
D
给你多个区间,如果有个数字被区间叠加超过k次,你必须撤掉一个线段,你得·取消最少的线段使得没有所有区间没有叠加超过k次。
解析:
首先肯定是先排序,排序完后就开始遍历,我们可以将有叠加的就存进来,当大于k了就删掉一个,那要删掉谁最好,那就是最右边的刚进来的一个,因为他最靠右,影响后面更多区间,所以删他就好。还有就是怎么判断叠加,我们将容器里的第一个区间的右边界和最新的一个区间的左边界进行比较,如果小于,说明现在这个包括后面的区间都不可能有叠加,那就直接把第一个给踢掉,此处用while循环直到有叠加了。由于有重复元素,我们用multiset来存储
#include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++) #define per(i,j,k) for(int i=j;i>=k;i--) #define mp make_pair #define pb push_back using namespace std; #define pii pair<int,int> const int maxx = 2e5+6; multiset<pii>s; vector<int>ans; int n,k; struct node{ int l,r,id; }p[maxx]; bool cmp(node a,node b){ if(a.l==b.l) return a.r<b.r; else return a.l<b.l; } int main(){ while(~scanf("%d %d",&n,&k)){ for(int i=1;i<=n;i++){ scanf("%d%d",&p[i].l,&p[i].r); p[i].id=i; } sort(p+1,p+1+n,cmp); ans.clear(); for(int i=1;i<=n;i++){ while(s.size()&&(*s.begin()).first<p[i].l) s.erase(s.begin()); s.insert(make_pair(p[i].r,p[i].id)); while(s.size()>k){ auto it=s.end();it--;ans.pb((*it).second);s.erase(it); } } int sz=ans.size(); printf("%d\n",sz); for (int i=0;i<sz;i++){ if(i)printf(" %d",ans[i]); else printf("%d",ans[i]); } printf("\n"); } return 0; }
E
简单dp
#include<bits/stdc++.h> #define LL long long #define lson rt<<1 #define rson rt<<1|1 using namespace std; const int maxx = 2e5+6; LL a[maxx]; LL b[maxx]; LL n,c; LL dp[maxx][3]; int main(){ while(~scanf("%lld%lld",&n,&c)){ for (int i=2;i<=n;i++){ scanf("%lld",&a[i]); } for (int i=2;i<=n;i++){ scanf("%lld",&b[i]); } dp[1][1]=0; dp[1][2]=c; for (int i=2;i<=n;i++){ dp[i][1]=min(dp[i-1][1]+a[i],dp[i-1][2]+a[i]); dp[i][2]=min(dp[i-1][2]+b[i],dp[i-1][1]+b[i]+c); } for (int i=1;i<=n;i++){ if (i-1)printf(" %lld",min(dp[i][1],dp[i][2])); else printf("0"); } printf("\n"); } }
F
给你一棵树,每个节点有自己的权值,每个节点都由边权为1的边连着,你需要挑选几个点出来,点权值最大,且任意两个点间的边应大于k。
贪心:我们给出下面这样一棵树
(A)
/ \
(B) (C)
/ \ / \
(D) (E) (F) (G)
我们令k=1;例如我们选中B这个点由这个点进行dfs,那D,E,A就是不可选的,因为没有大于K=1;那我们将DEA都减掉B的点值,后面遍历的时候,如果发现有的点是负值说明他是比我们所选的B点值小的
那万一B点不是最优点呢,那就会出现有的点比他大的被减后不是负数,例如B=2,A=10,选了B后,A=8,后面遍历到A的时候发现A是正的,说明前面所加上的并不是最优的,那我们把正的点继续加起来。
那么问题来了,应该怎么遍历每一个点。是从上往下还是从下往上,
有这里可知 (27)
/ \
(15) (15)
当k=1,如果从上往下,会发现答案只是27
从下往上答案是15+15;
为什么会这样?根据前面的贪心 思路,我们是根据一个点开始得出下面的距离小于等于k的,说粗俗点,由点值大小对比其他点来决定要不要选这个点,用负正来判断,
所以从上往下,你会发现一个“上”这个点对应的可是下面多个点,这样下来,如A下面的BC,面对下面有的正有的负,你是选还是不选这个“上”也就是A这个点,相反我们由下到上,那么经过下面多个点例如BC,通过先假定BC这些为最优点,再出力A,因为BC这些肯定是满足要求的,所以这时就变成了,是选A还是选BC,满足题意;
所以我们先bfs,将每个点的深度求出来,然后从深度大的往小的遍历。
#include<bits/stdc++.h> #define LL long long #define pii pair<int,int> #define mp make_pair #define pb push_back using namespace std; const int maxx = 1005; int ver[maxx],Next[maxx],head[maxx]; int vis[maxx]; int a[maxx]; int n,k,tot; vector<int>b; void add(int x,int y){ ver[++tot]=y;Next[tot]=head[x];head[x]=tot; ver[++tot]=x;Next[tot]=head[y];head[y]=tot; } void bfs(int st){ queue<pii>q; q.push(mp(st,0)); while(q.size()){ int u=q.front().first; int dep=q.front().second; b.pb(u); q.pop(); vis[u]=1; for (int i=head[u];i;i=Next[i]){ int v=ver[i]; if (!vis[v]){ q.push(mp(v,dep+1)); } } } } int dfs(int x){ for (int i=1;i<=n;i++){ vis[i]=0; } queue<pii>q; while(q.size())q.pop(); q.push(mp(x,0)); int c=a[x]; while(q.size()){ int u=q.front().first; a[u]-=c; vis[u]=1; int dep=q.front().second; q.pop(); for (int i=head[u];i;i=Next[i]){ int v=ver[i]; if (vis[v])continue; if (dep<k){ q.push(mp(v,dep+1)); } } } return c; } int main(){ while(~scanf("%d%d",&n,&k)){ for (int i=1;i<=n;i++){ scanf("%d",&a[i]); } int uu,vv; for (int i=1;i<n;i++){ scanf("%d%d",&uu,&vv); add(uu,vv); } bfs(1); reverse(b.begin(),b.end()); int sz=b.size(); int ans=0; for (int i=0;i<sz;i++){ if (a[b[i]]>0)ans+=dfs(b[i]); } printf("%d\n",ans); } return 0; }