UPC第38,39,40场部分题解

第38场

A. Bovine Alliance

Description

Bessie and her bovine pals from nearby farms have finally decided that they are going to start connecting their farms together by trails in an effort to form an alliance against the farmers. The cows in each of the N (1 <= N <= 100,000) farms were initially instructed to build a trail to exactly one other farm, for a total of N trails. However months into the project only M (1 <= M < N) of these trails had actually been built. Arguments between the farms over which farms already built a trail now threaten to split apart the cow alliance. To ease tension, Bessie wishes to calculate how many ways the M trails that exist so far could have been built. For example, if there is a trail connecting farms 3 and 4, then one possibility is that farm 3 built the trail, and the other possibility is that farm 4 built the trail. Help Bessie by calculating the number of different assignments of trails to the farms that built them, modulo 1,000,000,007. Two assignments are considered different if there is at least one trail built by a different farm in each assignment.
给出n个点m条边的图,现把点和边分组,每条边只能和相邻两点之一分在一组,点可以单独一组,问分组方案数。

Input

​ Line 1: Two space-separated integers N and M

  • Lines 2…1+M: Line i+1 describes the ith trail. Each line contains two space-separated integers u_i and v_i (1 <= u_i, v_i <= N, u_i != v_i) describing the pair of farms connected by the trail. Note that there can be two trails between the same pair of farms.

Output

  • Line 1: A single line containing the number of assignments of trails to farms, taken modulo 1,000,000,007. If no assignment satisfies the above conditions output 0.

Sample Input

5 4

1 2

3 2

4 5

4 5

Sample Output

6

HINT

OUTPUT DETAILS: There are 6 possible assignments. Letting {a,b,c,d} mean that farm 1 builds trail a, farm 2 builds trail b, farm 3 builds trail c, and farm 4 builds trail d, the assignments are: {2, 3, 4, 5} {2, 3, 5, 4} {1, 3, 4, 5} {1, 3, 5, 4} {1, 2, 4, 5} {1, 2, 5, 4}

显然要用到dfs求连通块,累计方法时注意使用乘法原理,当我们求出一个连通块后,要看点数和边数之间的关系,依题意只有两种成立,点数和边数相等的时候,是一个环,所以有两种,点数=边数+1时,有点数种,也就是说你把其中一个点孤立起来,其他正常连起来。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=200010;
struct edge
{int next ,to;
}e[N];
int head[N],num=1,vis1[N],vis2[N];  //vis1标记点,vis2标记边
void add(int from,int to)  //邻接表存图
{e[++num].next=head[from];e[num].to=to;head[from]=num;
}
ll  v,e1;
void dfs(int u)
{v++;vis1[u]=1;for(int i=head[u];i;i=e[i].next){if(!vis2[i]){vis2[i]=1;vis2[i^1]=1; // 将用过的边标记e1++;if(!vis1[e[i].to]){dfs(e[i].to); //搜索下一个点}}}}
int main()
{int n,m,x,y;cin >> n >>m;while(m--){cin >> x >> y;add(x,y);add(y,x);}ll ans=1;for(int i=1;i<=n;i++){if(!vis1[i]){v=0;e1=0;dfs(i);if(e1>v){cout << 0 << endl;    //注意这时无法满足题目条件return 0;}if(v==e1) ans=ans*2%mod;else ans=ans*v%mod; }}cout << ans ;return 0;
}

B.Grazing Patterns

Due to recent budget cuts, FJ has downsized his farm so that the grazing area for his cows is only a 5 meter by 5 meter square field! The field is laid out like a 5x5 grid of 1 meter by 1 meter squares, with (1,1) being the location of the upper-left square, and (5,5) being the location of the lower-right square:
(1,1) (1,2) (1,3) (1,4) (1,5)
(2,1) (2,2) (2,3) (2,4) (2,5)
(3,1) (3,2) (3,3) (3,4) (3,5)
(4,1) (4,2) (4,3) (4,4) (4,5)
(5,1) (5,2) (5,3) (5,4) (5,5)

Every square in this grid is filled with delicious grass, except for K barren squares (0 <= K <= 22, K even), which have no grass. Bessie the cow starts grazing in square (1,1), which is always filled with grass, and Mildred the cow starts grazing in square (5,5), which also is always filled with grass.

Each half-hour, Bessie and Mildred finish eating all the grass in their respective squares and each both move to adjacent grassy squares (north, south, east, or west). They want to consume all the grassy squares and end up in exactly the same final location. Please compute the number of different ways this can happen. Bessie and Mildred always move onto grassy squares, and they never both move onto the same square unless that is the very last grassy square remaining.

给你一个5*5方格,有一些点不能走,求不重复走且走完所有可以走的方格,从起点走到终点的所有方案数。

输入

* Line 1: The integer K.
* Lines 2…1+K: Each line contains the location (i,j) of a non-grassy square by listing the two space-separated integers i and j.

输出

* Line 1: The number of different possible ways Bessie and Mildred can walk across the field to eat all the grass and end up in the same final location.

样例输入

4
3 2
3 3
3 4
3 1

样例输出

1

把题看懂,无脑dfs,注意递归函数中结束的条件是走到终点且把能走的全走。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#define ll long long
using namespace std;
const int N=200010;
int n,m,k,a,b,c,fl,t,x,y;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int vis[10][10];
int ans=0;
void dfs(int x,int y,int sum)
{if(x==5&&y==5&&sum==25){++ans;return;}for(int i=0;i<4;++i){int xx=x+dx[i];int yy=y+dy[i];if(xx>=1&&xx<=5&&yy>=1&&yy<=5&&!vis[xx][yy]){vis[xx][yy]=1;dfs(xx,yy,sum+1);vis[xx][yy]=0;}}
}
int main()
{cin >> k;for(int i=1;i<=k;++i){cin >> x >> y;vis[x][y]=1;}vis[1][1]=1;dfs(1,1,k+1);cout << ans ;return 0;
}

C. Mountain Climbing

Farmer John has discovered that his cows produce higher quality milk when they are subject to strenuous exercise. He therefore decides to send his N cows (1 <= N <= 25,000) to climb up and then back down a nearby mountain!

Cow i takes U(i) time to climb up the mountain and then D(i) time to climb down the mountain. Being domesticated cows, each cow needs the help of a farmer for each leg of the climb, but due to the poor economy, there are only two farmers available, Farmer John and his cousin Farmer Don. FJ plans to guide cows for the upward climb, and FD will then guide the cows for the downward climb. Since every cow needs a guide, and there is only one farmer for each part of the voyage, at most one cow may be climbing upward at any point in time (assisted by FJ), and at most one cow may be climbing down at any point in time (assisted by FD). A group of cows may temporarily accumulate at the top of the mountain if they climb up and then need to wait for FD’s assistance before climbing down. Cows may climb down in a different order than they climbed up.

Please determine the least possible amount of time for all N cows to make the entire journey.

农场主约翰发现他的奶牛剧烈运动后产奶的质量更高,所以他决定让N头(1 <= N <= 25,000)奶牛去附近爬山再返回来。第i头奶牛用时U(i)爬上山,用时D(i)下山。作为家畜,奶牛们每段路都要有农夫的帮助,可是由于经济疲软,农场里只有两个农夫John和Don。John计划引导奶牛爬山,Don引导奶牛下山。虽然每个奶牛都需要向导,但每段旅途只有一名农夫。所有任何时刻只有一头奶牛爬山也只能有一头奶牛下山,奶牛爬上山后,可以暂时停留在山顶上等待Don的帮助。奶牛上山的顺序和下山的顺序不一定要相同。

请计算出所有N 头牛完成旅程的最短时间。

输入

* Line 1: The number of cows, N.
* Lines 2…1+N: Line i+1 contains two space-separated integers: U(i) and D(i). (1 <= U(i), D(i) <= 50,000).

输出

* Line 1: A single integer representing the least amount of time for all the cows to cross the mountain.

样例输入

3
6 4
8 1
2 3

样例输出

17

显然网上一些结论为max(总上山时间+最快奶牛下山时间,总下山时间+最快奶牛上山时间)是错误的,这种事下意识认为第一头奶牛上山后,上下山都是一起进行的,无疑是错误的。

我们根据每头奶牛上下山的时间可以将奶牛们分为2类:

1.up<down ,2.down>up 相等的随意;

之后,考虑到up小的先到山顶不会拖慢后面的牛,我们把第一类都排在第二类前面,而且按up升序排;第二类牛我们按down降序排,这个没上面那个显然,但是原因也很简单,下的慢的先下可以拖住后面的牛下山,减少出现山顶的牛已经下完了,下面的牛还没上完这种浪费的情况;

排序后 ,O(n)模拟一下计算时间。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include<queue>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=70010;
struct node
{int up,down;static  bool cmp(const node &a ,const node &b)  //排序{if(a.up<a.down){if(b.up<b.down){return a.up<b.up;}else{return 1;}}else{if(b.up<b.down){return 0;}else{return a.down>b.down;}}}
}jk[N];
int up[N],down[N];
int main()
{int n;cin >> n;for(int i=1;i<=n;i++){cin >> jk[i].up >> jk[i].down;}sort(jk+1,jk+n+1,node::cmp);for(int i=1;i<=n;i++){up[i]=up[i-1]+jk[i].up;  //前缀和累计上山时间}for(int i=1;i<=n;i++){down[i]=max(down[i-1],up[i])+jk[i].down;  //down[i]为i头奶牛到达地面的时间,max是因为完全可以出现等待的情况}cout << down[n];return 0;
}

E.2nd Greatest Distance

There are N houses numbered 1 through N on a two-dimensional plane. House i is at (xi,yi).

We use Chebyshev distance to calculate the distance between two houses. That is, the distance between Houses i and j is max(|xi−xj|,|yi−yj|).

There are N(N−1)/2 pairs formed by two different houses. For each of these pairs, we will calculate the distance between the houses, and then we will sort these distances in descending order to get a sequence of length N(N−1)/2. Find the second value from the beginning of this sequence.

Constraints
All values in input are integers.
3≤N≤2×105

求max(|xi−xj|,|yi−yj|)次大值。

输入

Input is given from Standard Input in the following format:
N
x1 y1

xN yN

输出

Print the second value from the beginning of the sequence of distances of different houses sorted in descending order.

样例输入

【样例1】
3
0 0
1 2
4 0
【样例2】
4
0 0
0 0
1 0
0 1
【样例3】
20
407 361
167 433
756 388
-551 -47
306 -471
36 928
338 -355
911 852
288 70
-961 -769
-668 -386
-690 -378
182 -609
-677 401
-458 -112
184 -131
-243 888
-163 471
-11 997
119 544

样例输出

【样例1】
3
【样例2】
1
【样例3】
1766

SB题,改吐了。按x排一遍序,取前后各两个,把他们组合一下计算出数值存进新数组,之后标记用过。再按y排个序,还是取前后个两个,之后注意看有没有之前用过的组合,不要算重复。之后将新数组排序取次大就好了。

至于为什么在第一种时把所有组合都算一算,是因为方便标记。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#define ll long long
using namespace std;
const int N=200010;
int n,m,k,a,b,c,fl,t,x,y;
int l[20],l1[10];
int vis[N];
struct node
{int x;int y;int id;
}jk1[N],jk2[N];
bool cmp1(node x,node y)
{if(x.x==y.x){return x.y<y.y;}return x.x<y.x;
}
bool cmp2(node x,node y)
{if(x.y==y.y){return x.x<y.x;}return x.y<y.y;
}
int main()
{int n;cin >> n;for(int i=1;i<=n;i++){scanf("%d %d",&x,&y);jk1[i].x=x;jk2[i].x=x;jk1[i].y=y;jk2[i].y=y;jk1[i].id=i;jk2[i].id=i;}sort(jk1+1,jk1+n+1,cmp1);int k=1;l[++k]=max(abs(jk1[1].x-jk1[n].x),abs(jk1[1].y-jk1[n].y));vis[jk1[1].id]=1;vis[jk1[2].id]=1;vis[jk1[n-1].id]=1;vis[jk1[n].id]=1;l[++k]=max(abs(jk1[1].x-jk1[n-1].x),abs(jk1[1].y-jk1[n-1].y));if(n!=3){l[++k]=max(abs(jk1[2].x-jk1[n-1].x),abs(jk1[2].y-jk1[n-1].y));}l[++k]=max(abs(jk1[2].x-jk1[n].x),abs(jk1[2].y-jk1[n].y));l[++k]=max(abs(jk1[n].x-jk1[n-1].x),abs(jk1[n].y-jk1[n-1].y));l[++k]=max(abs(jk1[1].x-jk1[2].x),abs(jk1[1].y-jk1[2].y));sort(jk2+1,jk2+n+1,cmp2);if(!vis[jk2[2].id]||!vis[jk2[n].id])l[++k]=max(abs(jk2[2].x-jk2[n].x),abs(jk2[2].y-jk2[n].y));if(!vis[jk2[1].id]||!vis[jk2[n].id])l[++k]=max(abs(jk2[1].x-jk2[n].x),abs(jk2[1].y-jk2[n].y));if(n!=3){if(!vis[jk2[2].id]||!vis[jk2[n-1].id])l[++k]=max(abs(jk2[2].x-jk2[n-1].x),abs(jk2[2].y-jk2[n-1].y));}if(!vis[jk2[1].id]||!vis[jk2[n-1].id])l[++k]=max(abs(jk2[1].x-jk2[n-1].x),abs(jk2[1].y-jk2[n-1].y));// cout << endl;sort(l+1,l+k+1);//cout << k << endl;cout << l[k-1] << endl;//cout << l[7] << endl;return 0;
}

L: 组合数问题

​ 组合数表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3)三个物品中选择两个物品可以有(1, 2), (1, 3), (2, 3)这三种选择方法。根据组合数的定义,我们可以给出计算组合数[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mnni3KaZ-1628990998962)(http://exam.upc.edu.cn/upload/image/20161230/20161230141422_72219.jpg)] 的一般公式:

其中n! = 1×2×…×n。
小葱想知道如果给定n, m和k,对于所有的0≤i≤n,0≤ j≤min(i,m)有多少对(i, j)满足是k的倍数

​ 3≤n,m ≤2000,2≤k≤21,1≤t≤10000

求组合数杨辉三角打表,再用前缀和优化一下。

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#define ll long long
using namespace std;
const int N=3000;
int n,m,k,a,b,c,fl,t,x,y;
ll f[N][N],sum[N][N];
int main()
{cin >> t >> k;for(int i=1;i<=2005;i++)  //初始化{f[i][1]=i%k;f[i][i]=1;}for(int i=2;i<=2005;i++)  // 杨辉三角打表for(int j=2;j<i;j++)f[i][j]=(f[i-1][j]+f[i-1][j-1])%k;for(int i=1;i<=2005;i++) //前缀和优化{for(int j=1;j<=i;j++){if(f[i][j]==0) sum[i][j]=sum[i][j-1]+1;else sum[i][j]=sum[i][j-1];}}while(t--){ll ans=0;scanf("%d %d",&x,&y);for(int i=1;i<=x;i++){if(i>y) ans+=sum[i][y];else ans+=sum[i][i];}printf("%lld\n",ans);}return 0;
}

第39场

A.Rope Folding

题目描述

Farmer John has a long rope of length L (1 <= L <= 10,000) that he uses for various tasks around his farm. The rope has N knots tied into it at various distinct locations (1 <= N <= 100), including one knot at each of its two endpoints.

FJ notices that there are certain locations at which he can fold the rope back on itself such that the knots on opposite strands all line up exactly with each-other:

Please help FJ count the number of folding points having this property. Folding exactly at a knot is allowed, except folding at one of the endpoints is not allowed, and extra knots on the longer side of a fold are not a problem (that is, knots only need to line up in the areas where there are two strands opposite each-other). FJ only considers making a single fold at a time; he fortunately never makes multiple folds.

一个线段,有一些特殊的点,求有多少种折叠方法可以使折叠后特殊点一一对应,注意端点处不能折。

输入

* Line 1: Two space-separated integers, N and L.
* Lines 2…1+N: Each line contains an integer in the range 0…L specifying the location of a single knot. Two of these lines will always be 0 and L.

输出

* Line 1: The number of valid folding positions.

样例输入

5 10
0
10
6
2
4

样例输出

4

枚举这条线段所有点,注意不一定在整点折,可以在1.5这种地方折,所有枚举时候要考虑两种情况。

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=20010;
int n,a[N],x,m;
int check(int i)
{int ans=0;int k=0,fl=0;while(i>=k&&i+k<=m)  //注意结束条件,一端到头。{if(a[i-k]!=a[i+k]) {fl=1;break;}k++;}if(!fl&&i!=m){ans++;}fl=0,k=0;while(i>=k+1&&i+k<=m){if(a[i-k-1]!=a[i+k]){fl=1;break;}k++;}if(!fl) ans++;return ans;
}
int main()
{cin >> n >> m;for(int i=1;i<=n;i++){cin >> x;a[x]=1; // 标记}int sum=0;for(int i=1;i<=m;i++){sum+=check(i);}cout << sum << endl; return 0;
}

B. Insurance

Snuke has read his own fortune for tomorrow, and learned that there are N scenarios that can happen, one of which will happen tomorrow with equal probability. The i-th scenario will cost him Ai yen (Japanese currency).

Following this, Snuke has decided to get insurance today. If he pays x yen to his insurance company, he will get compensation of min(Ai,2x) yen when Ai yen is lost. Here, he can choose any non-negative real number as x.

Snuke wants to minimize the expected value of the amount of money he loses, which is x+Ai−min(Ai,2x). Find the minimized value.

Constraints
1≤N≤105
1≤Ai≤109
All values in input are integers.

输入

Input is given from Standard Input in the following format:
N
A1 A2 ⋯ AN

输出

Print the answer. Your answer will be judged correct when its absolute or relative error is at most 10−6.

样例输入

【样例1】
3
3 1 4
【样例2】
10
866111664 178537096 844917655 218662351 383133839 231371336 353498483 865935868 472381277 579910117

样例输出

【样例1】
1.83333333333333333333
【样例2】
362925658.10000000000000000000

数学题,我们要算的是:
K ∗ N + ∑ i = 1 n A [ i ] − m a x ( 2 K , A [ i ] ) ; K*N+\sum^n_{i=1}A[i]-max(2K,A[i]); K∗N+i=1∑n​A[i]−max(2K,A[i]);
求上面的最小值,函数应该是个下凸的,应该在 x = k / 2 x=k/2 x=k/2 取的,k应该是a[i]的中位数。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=200010;
int n;
double a[N],sum;
int main()
{cin >> n;for(int i=1;i<=n;i++){cin >> a[i];}sort(a+1,a+n+1);if(n==1)  //注意特判{printf("%.7f",a[1]/2.0);}else if(n==2){printf("%.7f",max(a[1],a[2])/2.0);}else{double k;if(n%2==1){k=a[n/2+1]/2.0;}else{k=(a[n/2]+a[n/2+1])/4.0;}//  cout << k << endl;for(int i=1;i<=n;i++){sum+=(a[i]-min(2*k,a[i]*1.0));}//cout << sum << endl;printf("%.7f",k+sum/n); //这里不要憨,k*n就爆了,化简一下。}return 0;
}

D.Many Formulae

题目描述

You are given a sequence of N non-negative integers: A1,A2,⋯,AN.

Consider inserting a + or - between each pair of adjacent terms to make one formula.

There are 2N−1 such ways to make a formula. Such a formula is called good when the following condition is satisfied:

  • - does not occur twice or more in a row.

Find the sum of the evaluations of all good formulae. We can prove that this sum is always a non-negative integer, so print it modulo (109+7).

Constraints
1≤N≤105
1≤Ai≤109
All values in input are integers.

给你一个数组,你可以在相邻两位之间选择+和-,并算出一个结果,最后所有可能的结果的和。

输入

Input is given from Standard Input in the following format:
N
A1 A2 ⋯ AN

输出

Print the sum modulo (109+7).

样例输入

【样例1】
3
3 1 5
【样例2】
4
1 1 1 1
【样例3】
10
866111664 178537096 844917655 218662351 383133839 231371336 353498483 865935868 472381277 579910117

样例输出

【样例1】
15
【样例2】
10
【样例3】
279919144

一眼DP,定义 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 为第i位前是加号的方案贡献总和,就是我们要求的数, d p [ i ] [ 1 ] dp[i][1] dp[i][1]就是第i位是减号的方案贡献总和。 s u m [ i ] [ 0 ] , s u m [ i ] [ 1 ] sum[i][0],sum[i][1] sum[i][0],sum[i][1]分别为第i位前是加号的方案和。

显然有如下方程:

       sum[i][0]=((sum[i-1][0]%mod+sum[i-1][1]%mod)%mod+mod)%mod;dp[i][0]=((dp[i-1][0]%mod+dp[i-1][1]%mod)%mod+(sum[i][0]%mod*a[i])%mod)%mod;sum[i][1]=sum[i-1][0]%mod;//两个减号不能连着dp[i][1]=(dp[i-1][0]%mod-(sum[i][1]*a[i])%mod+mod)%mod;

code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=200010;
ll dp[N][3];
ll sum[N][3];
ll a[N];
int main()
{int n;cin >> n;// dp[i][0]=dp[i-1][1]+dp[i-1][0];//dp[i][1]=dp[i-1][0];for(int i=1;i<=n;i++){cin >> a[i];}if(n==1){cout << a[1]%mod;return 0;}dp[2][0]=((a[1]+a[2])%mod+mod)%mod;dp[2][1]=((a[1]-a[2])%mod+mod)%mod;sum[2][1]=1;sum[2][0]=1;for(int i=3;i<=n;i++){sum[i][0]=((sum[i-1][0]%mod+sum[i-1][1]%mod)%mod+mod)%mod;dp[i][0]=((dp[i-1][0]%mod+dp[i-1][1]%mod)%mod+(sum[i][0]%mod*a[i])%mod)%mod;//  dp[i][0]%=mod;sum[i][1]=sum[i-1][0]%mod;dp[i][1]=(dp[i-1][0]%mod-(sum[i][1]*a[i])%mod+mod)%mod;}cout << (dp[n][1]+dp[n][0])%mod;return 0;
}

I.triples I

Doctor Elephant is testing his new program: output the bitwise or of the numbers inputed.
He has decided to input several multiples of 3 and the output of the program should be his favorite number a.
Because he is lazy, he decided to input as few numbers as possible. He wants you to construct such an input for every aa he chose.
It’s guaranteed that for every aa in the input there is such a solution. If there’re multiple solutions you can output any.

题目给出T组样例,每组包含一个数,要求分解为一些3的倍数的数字或操作的和,而其中这些数尽可能少,输出这些数(保证有解,解不一定唯一)

输入

There’re multiple test cases in a test file.
The first line contains a positive integer T - the number of test cases.
In each of the following T lines there is one positive integer a.

输出

For each test case output a line. First you need to output the number of numbers in your input, and then you need to output these numbers, separating by spaces.

样例输入

2
3
7

样例输出

1 3
2 3 6

思路:既然是按位或,那么肯定和二进制有关。显然,一个数的二进制中,奇数位上的1%3=1,偶数位上的1%3=2。那么我们就统计奇数位,偶数位上的个数并用数组记下。首先,我们最多用2个数肯定能凑出这个数。然后分类讨论。

1.a%3==0,显然就是只用a这一个数即可,否则肯定要用两个数。

2.a%3==1,我们就要想办法删去这个1。再次分类讨论:

(1)奇数位上的1和偶数位上的1都不为0,那么我们只需删去第一个奇数位上的1构造出第一个数(这个数肯定是3的倍数),然后再用上删去的那个数和第一个偶数位上的数构造出第二个数((1+2)%3==0,也肯定是3的倍数)。

(2)奇数位上的1不为0,偶数位上的1为0。那么我们也是只需删去第一个奇数位上的1构造出第一个数,再用上删去的那个数和其后的前2个奇数位的数(也就是用前三个奇数位上的数,(1+1+1)%3==0,是3的倍数)。

(3)奇数位上的1为0,偶数位上的1不为0。那么我们只需删去前两个偶数位上的数构造出第一个数((2+2)%31,删去后肯定是3的倍数),再用上删去的那两个数和其后的第一个偶数位的数(也就是用前三个偶数位上的数,(2+2+2)%30,是3的倍数)。

3.a%3==2,同理,我们要想办法删去这个2。再次分类讨论:

(1)奇数位上的1和偶数位上的1都不为0,那么我们只需删去第一个偶数位上的1构造出第一个数(这个数肯定是3的倍数),然后再用上删去的那个数和第一个奇数位上的数构造出第二个数((1+2)%3==0,也肯定是3的倍数)。

(2)奇数位上的1为0,偶数位上的1不为0。那么我们也是只需删去第一个偶数位上的1构造出第一个数,再用上删去的那个数和其后的前2个偶数位的数(也就是用前三个偶数位上的数,(2+2+2)%3==0,是3的倍数)。

(3)奇数位上的1不为0,偶数位上的1为0。那么我们只需删去前两个奇数位上的数构造出第一个数((1+1)%32,删去后肯定是3的倍数),再用上删去的那两个数和其后的第一个奇数位的数(也就是用前三个奇数位上的数,(1+1+1)%30,是3的倍数)。

注意:一定要用上删去的那若干个数,不然构造出两个数按位或后就不等于a。
这个转载至 https://blog.csdn.net/birdmanqin/article/details/97613063

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include<queue>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=50010;
ll num1[N],num2[N],bb[N];
int main()
{ll t,n;scanf("%lld",&t);while(t--){scanf("%lld",&n);ll sum1=0,sum2=0;ll k1=0,k2=0;memset(num1,0,sizeof(num1));memset(num2,0,sizeof(num2));//  memset(bb,0,sizeof(bb));if(n%3==0){printf("1 %lld\n",n);continue;}int cnt=0;for(int i=0;i<=60;i++){if(n&(1LL<<i)) //二进制枚举快{if((i+1)&1) num1[++k1]=(1LL<<i);else num2[++k2]=(1LL<<i);}}//  cout << k1 << " " << k2 << endl;if(n%3==1){if(k1>=2) printf("2 %lld %lld\n", n-num1[1],n-num1[2]);else if(k1==1) printf("2 %lld %lld\n", n-num1[1],num1[1]+num2[1]);else printf("2 %lld %lld\n", n-num2[1]-num2[2],num2[3]+num2[1]+num2[2]);}else{if(k2>=2) printf("2 %lld %lld\n", n-num2[1],n-num2[2]);else if(k2==1) printf("2 %lld %lld\n", n-num2[1],num1[1]+num2[1]);else printf("2 %lld %lld\n", n-num1[1]-num1[2],num1[3]+num1[1]+num1[2]);}}return 0;
}

L.meeting2019

A new city has just been built. There’re nn interesting places numbered by positive numbers from 1 to n.
In order to save resources, only exactly n−1 roads are built to connect these nn interesting places. Each road connects two places and it takes 1 second to travel between the endpoints of any road.
There is one person in each of the places numbered x1,x2…xk and they’ve decided to meet at one place to have a meal. They wonder what’s the minimal time needed for them to meet in such a place. (The time required is the maximum time for each person to get to that place.)

给你n个点的一棵树,结点编号1到n,有k个关键点,在树上找一个点,使得这k个关键点到这个点最远的距离最小,然后输出这个点到这k个关键点的最远距离。

输入

First line two positive integers, n,k - the number of places and persons.(1≤n≤105)
For each the following n−1 lines, there’re two integers a,b that stand for a road connecting place a and b. It’s guaranteed that these roads connected all n places.
On the following line there’re kk different positive integers x1,x2…xk separated by spaces. These are the numbers of places the persons are at.

输出

A non-negative integer - the minimal time for persons to meet together.

样例输入

4 2
1 2
3 1
3 4
2 4

样例输出

2

问题等价于求树的直径,最小距离即为直径除2向上取整。

有两种求法,一是动态规划,对于每个结点,把所有子结点的 d ( i ) d(i) d(i) (表示根为 i i i 的子树中根到叶子的最大距离)都求出来,设 d d d 值前两大的结点为 u u u 和 v v v,则 d ( u ) + d ( v ) + 2 d(u) + d(v) +2 d(u)+d(v)+2就是树的直径。

另一种是两次DFS,从任意一个关键节点开始,找到离它最远的关键结点 y y y,从 y y y 出发dfs找到新的最远结点 z z z,形成的就是直径。

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include<queue>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=200010;
struct node
{int u,v,next;
}e[N];
int num,p,vis[N],maxx;
int head[N],n,m;
void add(int u,int v)
{e[++num].u=u;e[num].v=v;e[num].next=head[u];head[u]=num;
}
void dfs(int u,int pre ,int sum)
{if(sum>maxx&&vis[u]){maxx=sum;p=u;}for(int i=head[u];i;i=e[i].next){int v=e[i].v;if(v==pre) continue; //防止成环dfs(v,u,sum+1);}
}
int main()
{memset(head,-1,sizeof(head));cin >> n >> m;for(int i=1;i<n;i++){int u,v;cin >> u >> v;add(u,v);add(v,u);}while(m--){int x;cin >> x;vis[x]=1;}dfs(1,0,0);maxx=0;dfs(p,0,0);cout << (maxx+1)/2;return 0;
}

第40场

E: Arithmetic Sequence

Given is a sequence of three integers A=(A1,A2,A3). On this sequence, you can do the following operation any number of times:
choose i∈{1,2,3} and add 1 to Ai.
Find the minimum number of operations needed to make A arithmetic. Here, the sequence A=(A1,A2,A3) is arithmetic when A2−A1=A3−A2 holds.

给你三个数,你可以执行把一个数加一任意次,问要达到 A2−A1=A3−A2最少多少次

Constraints
1≤A1,A2,A3≤1015

输入

Input is given from Standard Input in the following format:
A1 A2 A3

输出

Print the answer.

样例输入

【样例1】
4 8 10
【样例2】
10 3 4
【样例3】
1 2 3
【样例4】
1000000000000000 1 1000000000000000

样例输出

Increasing Triples【样例1】
2
【样例2】
4
【样例3】
0
【样例4】
999999999999999

$A_2−A_1=A_3−A_2 $ 也就是 2 A 2 = A 1 + A 3 2A_2=A_1+A_3 2A2​=A1​+A3​ 所以这里我们分两种情况讨论:

​ 1. 2 A 2 > A 1 + A 3 2A_2>A_1+A_3 2A2​>A1​+A3​像这种我们只需要执行 2 A 2 − A 1 − A 3 2A_2-A_1-A_3 2A2​−A1​−A3​次;

​ 2. 2 A 2 < A 1 + A 3 2A_2<A_1+A_3 2A2​<A1​+A3​时,我们要看 A 1 + A 3 A_1+A_3 A1​+A3​是不是偶数,不是偶数,执行 A 2 − ( A 1 + A 3 + 1 ) / 2 + 1 A_2-(A_1+A_3+1)/2+1 A2​−(A1​+A3​+1)/2+1;

是的话,为 A 2 − ( A 1 + A 3 ) / 2 A_2-(A_1+A_3)/2 A2​−(A1​+A3​)/2

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include<queue>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=50010;
ll num1[N],num2[N],bb[N];
int main()
{ll a,b,c;cin >> a >> b >> c;if(a+c>2*b){if((a+c)%2==0){cout << (a+c)/2-b << endl;}else{cout << (a+c+1)/2-b+1 << endl;}}else{cout << 2*b-a-c << endl;}return 0;
}

H.Increasing Triples

Given are three sequences of N integers each: A=(A1,…,AN),B=(B1,…,BN),C=(C1,…,CN).
You can permute each of these sequences in any way you like. Find the maximum possible number of indices i such that Ai<Bi<Ci after permuting them.

给你三个数组,让你随意排序,求最后满足 A i < B i < C i A_i<B_i<C_i Ai​<Bi​<Ci​的最大数

Constraints
1≤N≤105
1≤Ai,Bi,Ci≤109

输入

Input is given from Standard Input in the following format:
N
A1 A2 … AN
B1 B2 … BN
C1 C2 … CN

输出

Print the answer.

样例输入

【样例1】
5
9 6 14 1 8
2 10 3 12 11
15 13 5 7 4
【样例2】
1
10
20
30
【样例3】
3
1 1 1
1 1 2
2 2 2

样例输出

【样例1】
3
【样例2】
1
【样例3】
0

开三个优先队列来模拟一遍即可。

c o d e : code: code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <map>
#include<queue>
#include <iomanip>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=50010;
ll num1[N],num2[N],bb[N];
int main()
{priority_queue <int,vector<int>,greater<int> >q1,q2,q3;int n,ans=0;cin >> n;int x;for(int i=1;i<=n;i++){cin >> x;q1.push(x);}for(int i=1;i<=n;i++){cin >> x;q2.push(x);}for(int i=1;i<=n;i++){cin >> x;q3.push(x);}while(!q1.empty()){x=q1.top();q1.pop();while(!q2.empty()&&q2.top()<=x){q2.pop();}if(q2.empty()) break;x=q2.top();q2.pop();while(!q3.empty()&&q3.top()<=x){q3.pop();}if(q3.empty()) break;q3.pop();++ans;}cout << ans;return 0;
}

G.Cow IDs

Being a secret computer geek, Farmer John labels all of his cows with binary numbers. However, he is a bit superstitious, and only labels cows with binary numbers that have exactly K “1” bits (1 <= K <= 10). The leading bit of each label is always a “1” bit, of course. FJ assigns labels in increasing numeric order, starting from the smallest possible valid label – a K-bit number consisting of all “1” bits. Unfortunately, he loses track of his labeling and needs your help: please determine the Nth label he should assign (1 <= N <= 10^7).

FJ给他的奶牛用二进制进行编号,每个编号恰好包含K 个"1" (1 <= K <= 10),且必须是1开头。FJ按升序编号,第一个编号是由K个"1"组成。

请问第N(1 <= N <= 10^7)个编号是什么。

输入

* Line 1: Two space-separated integers, N and K.

输出

the Nth label he should assign

样例输入

7 3

样例输出

10110

首先我们要算出第n个编号有几个零,几个1;之后使用全排列函数就好了;

关于组合数:如果是3个1一个0的话,有 C 3 1 C_3^1 C31​种,3个1 2个0的话,有 C 4 2 C_4^2 C42​种 ,依此类推。

c o d e : code: code:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000000 + 10;
char s[maxn];
int main()
{int n,k,m=0,lr;cin >> n >> k;lr= 1;for (;n>lr;++m){n-=lr;lr =lr*(k+m)/(m+1);// cout << n << endl;}s[0]='1';for (int i=1; i<k+m;++i){if (i<=m)s[i]='0';else s[i] = '1';}//cout << n << endl;//cout << s << endl;while(--n && next_permutation(s+1,s+k+m));printf("%s\n",s);return 0;
}

F.Overplanting

Farmer John has purchased a new machine that is capable of planting grass within any rectangular region of his farm that is “axially aligned” (i.e.,with vertical and horizontal sides). Unfortunately, the machine malfunctions one day and plants grass in not one, but N (1 <= N <= 10)different rectangular regions, some of which may even overlap.

Given the rectangular regions planted with grass, please help FJ compute the total area in his farm that is now covered with grass.

让你求多个矩阵面积的并。

输入

* Line 1: The integer N.
* Lines 2…1+N: Each line contains four space-separated integers x1 y1 x2 y2 specifying a rectangular region with upper-left corner (x1,y1) and lower-right corner (x2,y2). All coordinates are in the range -10,000…10,000.

输出

* Line 1: The total area covered by grass.

样例输入

2
0 5 4 1
2 4 6 2

样例输出

20

这里可以使用扫描线加线段树,但是我太菜了???,这里使用矩阵切割算法:

用当前矩形去切割之前所有加入至矩形集合 S 中的矩形,将它们分成更多的小矩形,并再加入集合 S 中,并删除原来在集合 S 中的矩形,最后加入当前矩形。

假设目前插入的矩形为(x3,y3,x4,y4),则我们现在要用他来切割集合内的矩形(x1,y1,x2,y2)。

我们先在x轴方向上进行线段切割

k1=max(x1,x3)
k2=min(x2,x4)

则k1,k2即为两个矩形x轴上的交点。

倘若x1<k1,说明产生了新矩形(x1,y1,k1,y2)

倘若x2>k2,说明产生了新矩形(k2,y1,x2,y2);

再从y轴方向切割:

之后再把新矩形加到集合里,最后扫一遍集合计算面积和就好了。

c o d e : code: code:


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1005;
int n,tot=0;
struct node
{ll x1,y1,x2,y2;
}a[maxn];
void add(ll x1,ll y1,ll x2,ll y2)
{a[++tot]=(node){x1,y1,x2,y2};
}
void cnt(int p,ll x1,ll y1,ll x2,ll y2,int f)
{ll k1,k2;if(!f){k1=max(x1,a[p].x1);k2=min(x2,a[p].x2);if(a[p].x1<k1) add(a[p].x1,a[p].y1,k1,a[p].y2);if(k2<a[p].x2) add(k2,a[p].y1,a[p].x2,a[p].y2);cnt(p,k1,y1,k2,y2,1);}else{k1=min(y1,a[p].y1);k2=max(y2,a[p].y2);if(k1<a[p].y1) add(x1,a[p].y1,x2,k1);if(k2>a[p].y2) add(x1,k2,x2,a[p].y2);}
}
int main()
{cin >> n;ll x1,y1,x2,y2;cin >> x1 >> y1 >> x2 >> y2;add(x1,y1,x2,y2);//cout << tot << endl;for(int i=2;i<=n;i++){scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);for(int j=1;j<=tot;j++){if(a[j].x1>=x2||a[j].x2<=x1||a[j].y1<=y2||a[j].y2>=y1){continue;}cnt(j,x1,y1,x2,y2,0);a[j]=a[tot]; //将原来的删除,用最后一个覆盖。   tot--;j--;//cout << tot << endl;}add(x1,y1,x2,y2);}ll ans=0;// cout << tot << endl;for(int i=1;i<=tot;i++){ans+=(a[i].x2-a[i].x1)*(a[i].y1-a[i].y2);//cout << ans << endl;}cout << ans;return 0;
}

typora-user-images\image-20210815091307221.png" alt=“image-20210815091307221” style=“zoom:25%;” />

之后再把新矩形加到集合里,最后扫一遍集合计算面积和就好了。

c o d e : code: code:


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1005;
int n,tot=0;
struct node
{ll x1,y1,x2,y2;
}a[maxn];
void add(ll x1,ll y1,ll x2,ll y2)
{a[++tot]=(node){x1,y1,x2,y2};
}
void cnt(int p,ll x1,ll y1,ll x2,ll y2,int f)
{ll k1,k2;if(!f){k1=max(x1,a[p].x1);k2=min(x2,a[p].x2);if(a[p].x1<k1) add(a[p].x1,a[p].y1,k1,a[p].y2);if(k2<a[p].x2) add(k2,a[p].y1,a[p].x2,a[p].y2);cnt(p,k1,y1,k2,y2,1);}else{k1=min(y1,a[p].y1);k2=max(y2,a[p].y2);if(k1<a[p].y1) add(x1,a[p].y1,x2,k1);if(k2>a[p].y2) add(x1,k2,x2,a[p].y2);}
}
int main()
{cin >> n;ll x1,y1,x2,y2;cin >> x1 >> y1 >> x2 >> y2;add(x1,y1,x2,y2);//cout << tot << endl;for(int i=2;i<=n;i++){scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);for(int j=1;j<=tot;j++){if(a[j].x1>=x2||a[j].x2<=x1||a[j].y1<=y2||a[j].y2>=y1){continue;}cnt(j,x1,y1,x2,y2,0);a[j]=a[tot]; //将原来的删除,用最后一个覆盖。   tot--;j--;//cout << tot << endl;}add(x1,y1,x2,y2);}ll ans=0;// cout << tot << endl;for(int i=1;i<=tot;i++){ans+=(a[i].x2-a[i].x1)*(a[i].y1-a[i].y2);//cout << ans << endl;}cout << ans;return 0;
}

UPC第38,39,40场部分题解相关推荐

  1. 嵌入式开发38,39,40天(项目3:基于A8开发板的局域网聊天工具)

    开篇前言: 其实想了很久要不要写这个项目出来,毕竟这个项目用到的特殊库相对比较多,这也是网上那么少嵌入式项目开发的视频一样,在嵌入式的世界里,就是为了开发某个项目而裁剪硬件,裁剪系统,把不需要的全部抛 ...

  2. UPC第41场,第42场部分题解

    UPC第41场,第42场部分题解 第41场 A: LR Constraints We have N cards arranged in a row from left to right. We wil ...

  3. UPC第46场部分题解

    UPC第46场部分题解 这场简单题比较多,基本看懂题意就能A A: 小凯的疑惑(数论) A与B互质时,A与B最大不能表达出的数是多少? 打表找规律...结论为: ans=a∗b−a−bans=a*b- ...

  4. LeetCode第 227 场周赛题解

    LeetCode第 227 场周赛题解 检查数组是否经排序和轮转得到 原题链接 https://leetcode-cn.com/problems/check-if-array-is-sorted-an ...

  5. 广电总局:清理违规短视频账号38.39万个

    广电总局官网1月11日披露,自去年10月以来,开展为期2个月的短视频节目和账号专项治理工作,持续清理违规账号38.39万个,违规短视频节目102.40万条. 广电总局表示,一大批"伪正能量& ...

  6. 帧编码 场编码_去年,我帮助举办了40场编码活动。 这是我学到的。

    帧编码 场编码 by Florin Nitu 通过弗洛林·尼图 去年,我帮助举办了40场编码活动. 这是我学到的. (I helped host 40 coding events last year. ...

  7. 40+场面试,100%通过率,我想分享的14条经验

    来源 | 陈同学在搬砖 头图 | 下载于视觉中国 大家好,我是陈同学,首先来一个简单的自我介绍和个人的经历分享. 我的本科和硕士均就读于哈工大,在研究生期1年时间内自学操作系统.计算机网络.C++.数 ...

  8. 40+场面试,100%通过率,我想分享的 14 条经验

    作者 | 陈同学 来源 | 陈同学在搬砖(ID: chentongxueZBZ) 这里是陈同学,首先来一个简单的自我介绍,和个人的经历分享吧. 我本科和硕士均就读于哈工大,是今年1月毕业.我经历过3个 ...

  9. 20201015:力扣第210场周赛题解(上)

    力扣第210场周赛题解上 题目 思路与算法 代码实现 写在最后 题目 括号的最大嵌套深度 最大网络秩 思路与算法 第一题典型的栈数据结构求最大栈长的题目 第二题是一个经典的出入度题目,本题更加简单,统 ...

最新文章

  1. 计算机培训校本研修心得,精选校本培训心得体会三篇
  2. 【iOS报错】“this class is not key value coding-compliant for the key userPhoneNum”给字典设置键值对的时候报错...
  3. oracle 性能优化--索引总结
  4. 图片底下配的文字叫什么_38岁孙俪越来越有女人味!穿短裙配性感黑丝美腿撩人,短发超美...
  5. 20 岁发表 SCI 的学霸,梦想用算法改变世界
  6. 【maven】maven dependencyManagement 锁定Jar包版本
  7. 漫画:从打牌到 map-reduce 工作原理解析
  8. 漏洞编号 cve can bugtraq cncve cnvd cnnvd 简介
  9. 锐捷交换机堆叠配置举例
  10. 同时删除多个 Word 文档空白行
  11. mysql translate 函数_Oracle字符串函数-Translate()总结
  12. SQL中的表连接及子查询
  13. 移动端 touch 手机拖动 css停止问题
  14. 淘淘商城---8.8
  15. http://bigwhite.blogbus.com/logs/1347304.html
  16. 计算机软件开发如何提高效率,开发人员必知:提高工作效率的7个技巧
  17. php carbon 格式化,Laravel Carbon 简明使用
  18. 工作!!工作!!!工作!!!!
  19. 微信开发 --- 调用微信上传图片接口,并保存到自己的服务器
  20. linux 解压tgz文件

热门文章

  1. buuctf-[BJDCTF2020]ZJCTF,不过如此
  2. An Introduction to Shiro (formerly JSecurity) – A Beginner’s Tutorial Part 4
  3. 基于spring 的开源框架
  4. 多重采样和超级采样哪个流畅_测试之前你需要做这些功课
  5. 为大家推荐一款很不错的MarkDown编辑器——stackEdit
  6. VLAN:单臂路由全网通
  7. 跟我学UDS(ISO14229) ———— 0x10(DiagnosticSessionControl)
  8. python pyqt教程_python使用PyQt5的详细教程(代码示例)
  9. 看完这篇再也不怕 Redis 面试了
  10. 线性回归实验之成人死亡率预测