对于这套题目锐佬晚上分享啦自己的博客,太强啦。直接粘过来留着。博客分享
标题A - Jumping Machine Gym - 102860A
题目链接
Jumping Machine
Input file: standard input
Output file: standard output
Time limit: 1 second
Memory limit: 512 megabytes
Young inventor has created a new jumping machine. In order to test it, he brought it to the testing
polygon. The polygon is an infinite square grid.
Initially, the machine is located in the cell (0, 0). The machine has n springs, the i-th spring has the force
of li and allows the machine to jump li cells up or li cells to the right. Therefore this spring allows the
machine to get from cell (x, y) either to cell (x + li
, y), or to cell (x, y + li). After jumping, the spring is
thrown back and cannot be reused. The machine can use the springs in any order.
During the tests the cells, that the machine will fly over, will be stained with machine oil. In order not
to clean the grid after himself, the inventor has decided to put a protective mat on each cell the machine
could potentially fly over.
Now the inventor is wondering how many protective mats he needs to bring to the test with him.
Input
The first line of input contains n — the number of springs that the machine has (1 ≤ n ≤ 100). The
second line contains n integers li — the springs forces (li ≥ 1; 1 ≤ l1 + l2 + · · · + ln ≤ 106
).
Output
Output a single integer: the number of mats that inventor needs to bring.
Example
standard input standard output
2
4 2
22
Explanation
All the cells that can get dirty when the machine jumps in the example test are colored orange one the
figure below.
一共n个数,看能走过多少格子。
看的别的代码,大致看懂啦,在这里粘一下,附带一点个人理解。
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
//#include <>
using namespace std;
typedef long long int ll;
const int N = 1e6+10;
//unordered_
map<int ,int > ma;//注意本题需要用map进行映射,因为个数可能不多,但是ma里面存的东西(下标)真的够大
int n, l[N],dp[N],sum1[N];
vector<int >s;
int main()
{
scanf("%d",&n);
ll sum=0,i,j;
for(i=1;i<=n;i++){
scanf("%d",&l[i]);
sum+=l[i];
}
dp[0]=1;
for(i=1;i<=n;i++){
for(j=sum;j>=l[i];j--){
if(dp[j-l[i]]&&!dp[j]){
dp[j]=1;
s.push_back(j);
}
}
}
sort(s.begin(),s.end());
int len=s.size();
for(i=0;i<len;i++){
ma[s[i]]=i+1;//求一下竖行编号。
}
ll ans = 2*sum+1;
for(i=1;i<sum;i++){
if(dp[i]){
ans+=sum-i;//jiashang meiyishuhang de shuliang;
}
}
for(i=1;i<sum;i++){
if(dp[i]){
ans+=i-ma[i];//竖着从左往右看图,对于每一个拐点都是当前节点之前有几个竖行然后i-那些竖行就是剩余的格子数。
}
}
cout<<ans<<endl;
return 0;
}
标题B - Triangles and a Circle Gym - 102860B
You are given n distinct points on a circle of length L.
You need to find the number of triangles with vertices in these points that contain the center of the circle inside, or on their border.
Input
The first line of input contains two integers n and L (3≤n≤300000, n≤L≤109).
Let’s choose any point on the circle and call it S. Then any point A on the circle can be encoded as x, 0≤x<L: clockwise distance from S to A. We will call this number a coordinate of A.
The second line contains n distinct integers x1,x2,…,xn: coordinates of the given points on the circle (0≤xi<L).
Output
Print one integer: the number of triangles with vertices in the given points, that contain the center of the circle inside or on their border.
Examples
Input
3 10
0 1 2
Output
0
Input
10 10
0 1 2 3 4 5 6 7 8 9
Output
60
Sponsor
题意,就是给一个圆周长(0——len-1),然后在上面有坐标点,问选取三个坐标点构成的三角形有多少个能包含圆心或者使得圆心落在三角形边上。
思路:选取相邻的点,只要他们之间的差值比len/2小就是不可能构成复合条件的三角形。这样确定最后一个点r取在l到r-1的点中任意选取两个都能保证符合并且不和前面求过的不符合的情况一样。取一周,就好啦。
自己用尺取法写的,直接废物。我就是个废物。。。
最后学长帮我解决啦。是因为我的l的存值是错的。会漏解。
行就这样。然后代码:
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
//#include <>
using namespace std;
typedef long long int ll;
ll b[350000];
ll a[950000];
ll q[350000];
ll ccc2(ll n)
{
return n*(n-1)/2;
}
ll ccc3(ll n)
{
return n*(n-1)*(n-2)/6;
}
int main()
{
ll n,m,j,i,k,len;
scanf("%lld%lld",&n,&len);
for(int i=0;i<n;i++){
scanf("%lld",&b[i]);
}
sort(b,b+n);
for(ll i=0;i<n;i++)
{
a[i+n]=a[i]=b[i]*2;
a[i+n]+=len*2;
}
ll l,r,sum,num;
ll ban=len;
ll ans=ccc3(n);
r=l=0;
memset(q,0,sizeof(q));
while(r!=2*n&&l<=n-1)
{
if(a[r]-a[l]<ban)
{
r++;
}
else
{q[l]=max(q[l],ccc2(r-l-1));
l++;}
}
for(int i=0;i<n;i++)
{
ans-=q[i];
}
cout<<ans<<endl;
return 0;
}
学长说的那种短小型尺取法:
破而后立:
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
//#include <>
using namespace std;
typedef long long int ll;
ll b[350000];
ll a[950000];
ll ccc2(ll n)
{
return n*(n-1)/2;
}
ll ccc3(ll n)
{
return n*(n-1)*(n-2)/6;
}
int main()
{
ll n,m,j,i,k,len;
scanf("%lld%lld",&n,&len);
for(int i=0;i<n;i++){
scanf("%lld",&b[i]);
}
sort(b,b+n);
for(ll i=0;i<n;i++)
{
a[i+n]=a[i]=b[i]*2;
a[i+n]+=len*2;
}
ll l,r,sum,num;
ll ban=len;
ll ans=ccc3(n);
r=l=0;
for(ll i=0;i<n;i++)
{
while(a[r]-a[i]<ban) r++;
ans-=ccc2(r-i-1);
}
cout<<ans<<endl;
return 0;
}
最后加一句话,我们将那个所有数字都乘以2,对于就没有啦除以 2的操作,这样就可以遇到⚪的周长是奇数我们也不用管直接算就行啦。还有一个就是一定要排序,我一开始没有排序一直wa4
最后在来一份二分lower——bound版本的,(偷看学长的代码)真香
#include <iostream>
#include <bits/stdc++.h>
#include <algorithm>
//#include <>
using namespace std;
typedef long long int ll;
ll b[350000];
ll a[950000];
ll q[350000];
ll ccc2(ll n)
{
return n*(n-1)/2;
}
ll ccc3(ll n)
{
return n*(n-1)*(n-2)/6;
}
int main()
{
ll n,m,j,i,k,len;
scanf("%lld%lld",&n,&len);
for(int i=0;i<n;i++){
scanf("%lld",&b[i]);
}
sort(b,b+n);
for(ll i=0;i<n;i++)
{
a[i+n]=a[i]=b[i]*2;
a[i+n]+=len*2;
}
ll l,r,sum,num;
ll ban=len;
ll ans=ccc3(n);
for(int i=0;i<n;i++)
{
r=lower_bound(a,a+2*n,a[i]+ban)-a-1;
ans-=ccc2(r-i);
}
cout<<ans<<endl;
return 0;
}
尺取快,尺取140,用二分170😕