Codeforces Round #665 (Div. 2) (A B C D E)
Practice link: https://codeforces.ml/contest/1401
A. Distance and Axis
思路:1、n-k<=0,就让A点移到k位置,B点在0位置,答案即 k-n。
2、n-k>0,就找中点,如果n-k不是偶数则把A点移动到n+1,即答案是1,否则答案是0。
代码:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 998244353 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 22 using namespace std; 23 24 int main() 25 { 26 int t; 27 int n,k; 28 cin>>t; 29 while(t--){ 30 scanf("%d %d",&n,&k); 31 if(k>=n){ 32 printf("%d\n",k-n); 33 }else{ 34 if((n-k)%2==1){ 35 printf("1\n"); 36 }else{ 37 printf("0\n"); 38 } 39 } 40 } 41 return 0; 42 }
B. Ternary Sequence
思路:让答案最大,就要让正数最多,即a数组取2,b数组取1的数量尽量多,让负数最少,即a数组取1,b数组取2的数量尽量少,那么可以先取第一种贡献为2的,然后对于无贡献的情况(即a中元素为0或b中元素为0或者a=b),让a中的0尽量消耗b中的2。最后,如果b中的2还有剩余,则加上负贡献,即b中2的剩余数*2。
代码:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 998244353 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 22 using namespace std; 23 24 int main() 25 { 26 int t; 27 int a,b,c; 28 int aa,bb,cc; 29 cin>>t; 30 while(t--){ 31 ll sum=0; 32 scanf("%d%d%d",&a,&b,&c); 33 scanf("%d%d%d",&aa,&bb,&cc); 34 int num=min(c,bb); 35 sum+=num*2; 36 c-=num; 37 bb-=num; 38 num=min(cc,c); 39 cc-=num; 40 c-=num; 41 if(cc!=0){ 42 num=min(a,cc); 43 cc-=num; 44 a-=num; 45 if(cc!=0){ 46 sum-=2*cc; 47 } 48 } 49 printf("%lld\n",sum); 50 } 51 return 0; 52 }
C. Mere Array
思路:设这个数组中最小值为minn,如果两个数( x1 , x2 )之间可以互换位置,那么就说明 gcd(minn,x1) = gcd(minn,x2) = minn ,根据这个想法,我们用两个数组分别储存有序的数组b和原本无序的数组a,如果a与b中相同位置的元素不同,那么这个元素就需要与b中那个元素互换位置,我们只需要看这两个元素是否符合条件即可。
代码:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 998244353 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 22 using namespace std; 23 24 inline int gcd(int a,int b) { 25 return b>0 ? gcd(b,a%b):a; 26 } 27 int a[100005]; 28 int b[100005]; 29 30 int main() 31 { 32 int t; 33 int n; 34 cin>>t; 35 while(t--){ 36 scanf("%d",&n); 37 int minn=INF; 38 for(int i=1;i<=n;i++){ 39 scanf("%d",&a[i]); 40 b[i]=a[i]; 41 minn=min(a[i],minn); 42 } 43 sort(b+1,b+n+1); 44 int k=1; 45 for(int i=1;i<=n;i++){ 46 if(a[i]!=b[i]){ 47 if(gcd(a[i],minn)!=minn||gcd(b[i],minn)!=minn){ 48 k=0; 49 break; 50 } 51 } 52 } 53 if(k){ 54 printf("YES\n"); 55 }else{ 56 printf("NO\n"); 57 } 58 } 59 return 0; 60 } 61
D. Maximum Distributed Tree
题意:给你一棵树,再给你一些素数(乘积为k),让你给这棵树上的每条边填上权值,且要所有边的权值的乘积为 k,让 1 的数量尽量少,让你求
的最大值(f( i , j )指的是 i 和 j 之间的最短距离)。
思路:我们考虑每条边的使用次数,对于边( u , v ),可以分成包含 u 和 v 的两个集合,设包含 u 的集合含有元素为 d[ u ] 个,那么可以推出边( u , v )会被经过 d[ u ] * ( n-d[ u ] )次,把每条路径的经过次数加入到一个数组a 中,并把数组从大到小排序,因为求最大值,自然就是让经过次数最多路径的权值最大。对于给的那些素数也从大到小进行排序。
下面考虑权值分配,需要让 1 的数量最少。
1、m<=n-1,此时 1 的数量就是 n-1-m,要让得到的值最大,就是在素数数组最后加上 n-1-m 个 1,最后按顺序加那些乘值即可。
2、m>n-1,此时 1 的数量就是 0,对于多出来的素数,就可以把 1~m-(n-1)+1 个素数相乘得到一个超大素数,作为素数数组的第一个值,最后按顺序家那些乘值即可。
代码:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 1000000007 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 22 using namespace std; 23 const int maxn=100005; 24 25 int head[maxn]; 26 int num=0; 27 struct edg{ 28 int next,to,w; 29 }edge[maxn]; 30 void add_edge(int u,int v,int w) 31 { 32 num++; 33 edge[num].next=head[u];edge[num].to=v;edge[num].w=w;head[u]=num; 34 edge[++num].next=head[v];edge[num].to=u;edge[num].w=w;head[v]=num; 35 } 36 //----------- 37 vector<int>g[maxn]; 38 int dis[maxn]; 39 ll a[maxn]; 40 int pri[maxn]; 41 int n,k; 42 int pp=0; 43 bool cmp(ll x,ll y) 44 { 45 return x>y; 46 } 47 void dfs(int u,int fa) 48 { 49 dis[u]=1; 50 for(int i=0;i<g[u].size();i++){ 51 int v=g[u][i]; 52 if(v==fa)continue; 53 dfs(v,u); 54 dis[u]+=dis[v]; 55 a[++pp]=1ll*dis[v]*(n-dis[v]); 56 } 57 } 58 int main() 59 { 60 int t; 61 cin>>t; 62 while(t--){ 63 num=0; 64 pp=0; 65 scanf("%d",&n); 66 for(int i=1;i<=n;i++){ 67 g[i].clear(); 68 dis[i]=0; 69 a[i]=0; 70 } 71 for(int i=1;i<n;i++){ 72 int u,v; 73 scanf("%d%d",&u,&v); 74 g[u].push_back(v); 75 g[v].push_back(u); 76 } 77 scanf("%d",&k); 78 for(int i=1;i<=k;i++){ 79 scanf("%d",&pri[i]); 80 } 81 dfs(1,-1); 82 sort(a+1,a+n,cmp); 83 sort(pri+1,pri+1+k,cmp); 84 ll sum=0; 85 if(k<=n-1){ 86 for(int i=1;i<=k;i++){ 87 sum+=((a[i]%MOD)*(pri[i]%MOD))%MOD; 88 sum=sum%MOD; 89 } 90 for(int i=k+1;i<n;i++){ 91 sum+=a[i]; 92 sum=sum%MOD; 93 } 94 }else{ 95 int ans=k-n+2; 96 ll m=1; 97 for(int i=1;i<=ans;i++){ 98 m*=pri[i]; 99 m=m%MOD; 100 } 101 sum+=((a[1]%MOD)*(m%MOD))%MOD; 102 sum=sum%MOD; 103 for(int i=ans+1;i<=k;i++){ 104 sum+=((a[i-ans+1]%MOD)*(pri[i]%MOD))%MOD; 105 sum=sum%MOD; 106 } 107 } 108 printf("%lld\n",sum%MOD); 109 } 110 return 0; 111 }
E. Divide Square
题意:给你一个 1e6*1e6 的正方形,给你在这个正方形中的 n 条水平线、m条竖直线,问你这些线把这个正方形割成了多少个独立不联通部分。
思路:首先观察,可以看出答案就是 1+正方形内的交点+一下把大正方形分成两部分的线段数 ,问题就在怎么求正方形内的交点。
对 0~1e6 这个区间上的所有 x 进行枚举,用平行于y轴的直线扫描所有横向线段,遇到横向线段的起始点就再其对应的纵坐标上加一,遇到横向线段结束时就减一。如果某个竖直线段(x=ix=i上)与水平线段(y=jy=j上)相交,那么当扫描线与x=ix=i重合时,扫描线的第j位一定是一。这样就可以用扫描线与竖直线段重合部分的区间和表示与其相交的水平线段的个数。
代码:
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<string> 7 #include<vector> 8 #include<stack> 9 #include<bitset> 10 #include<cstdlib> 11 #include<cmath> 12 #include<set> 13 #include<list> 14 #include<deque> 15 #include<map> 16 #include<queue> 17 #define ll long long 18 #define MOD 1000000007 19 #define INF 0x3f3f3f3f 20 #define mem(a,x) memset(a,x,sizeof(a)) 21 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 22 using namespace std; 23 const int maxn=1000005; 24 25 int head[maxn]; 26 int num=0; 27 struct edg{ 28 int next,to,w; 29 }edge[maxn]; 30 void add_edge(int u,int v,int w) 31 { 32 num++; 33 edge[num].next=head[u];edge[num].to=v;edge[num].w=w;head[u]=num; 34 edge[++num].next=head[v];edge[num].to=u;edge[num].w=w;head[v]=num; 35 } 36 //----------- 37 int n,m; 38 ll tr[maxn]; 39 pair<int,int>pr; 40 vector<pair<int,int> >a[maxn],b[maxn]; 41 int lowbit(int x) 42 { 43 return (x)&(-x); 44 } 45 void update(int x,int k) 46 { 47 while(x<=1000000){ 48 tr[x]+=k; 49 x+=lowbit(x); 50 } 51 } 52 ll getsum(int x) 53 { 54 ll res=0; 55 while(x){ 56 res+=tr[x]; 57 x-=lowbit(x); 58 } 59 return res; 60 } 61 int main() 62 { 63 ll ans=1; 64 scanf("%d %d",&n,&m); 65 for(int i=1;i<=n;i++){ 66 int y,lx,rx; 67 scanf("%d %d %d",&y,&lx,&rx); 68 a[lx].push_back(make_pair(y,1)); 69 a[rx+1].push_back(make_pair(y,-1)); 70 if(lx==0&&rx==1000000)ans++; 71 } 72 for(int i=1;i<=m;i++){ 73 int x,ly,ry; 74 scanf("%d %d %d",&x,&ly,&ry); 75 b[x].push_back(make_pair(ly,ry)); 76 if(ly==0&&ry==1000000)ans++; 77 } 78 for(int i=0;i<=1000000;i++){ 79 for(auto it:a[i]){ 80 update(it.first,it.second); 81 } 82 for(auto it:b[i]){ 83 ll temp1,temp2; 84 if(it.first==0){ 85 temp1=0; 86 }else{ 87 temp1=getsum(it.first-1); 88 } 89 temp2=getsum(it.second); 90 ans+=temp2-temp1; 91 } 92 } 93 printf("%lld\n",ans); 94 return 0; 95 }