A. Heist
水题,扫一遍然后记录最大值和最小值,ans = max-min+1-n;
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int maxa = 0,mina = 0x3f3f3f3f;
for(int i = 0; i < n; i++)
{
int x;
scanf("%d",&x);
mina = min(mina,x);
maxa = max(maxa,x);
}
printf("%d\n",maxa-mina-n+1);
return 0;
}
B. Buying a TV Set
水题,先用gcd将x/y化成最简分式,然后 ans = min(a/x,b/y);注意用long long!
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a, LL b)
{
return b == 0 ? a : gcd(b,a%b);
}
int main()
{
LL a,b,x,y;
scanf("%lld%lld%lld%lld",&a,&b,&x,&y);
LL e = gcd(x,y);
x = x/e;
y = y/e;
//cout << e <<endl;
//cout << a/x << " " << b/y <<endl;
LL ans = min(a/x,b/y);
printf("%lld\n",ans);
return 0;
}
C. Coffee Break 贪心, 一个个放,当满足a[j] - a[i] -1 >= d 时可以放到a[i] 后,i 从小到大,
首先用set + lower_bound 做,nlgn 的算法,结果TLE了~
然后发现正解是用queue 直接模拟,o(n)就好了,每次都和队首元素进行比较,如果满足条件,它所在的天和队首元素一样,它入队,队首元素出队;否则,他所在的天=++count,count为当前已经记录的天数,它入队。ans = count.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
typedef pair <LL,int> P;
int n,m,d;
int a[maxn],b[maxn];
map <int,int> mp;
int main()
{
scanf("%d%d%d",&n,&m,&d);
for(int i = 0; i < n; i++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(a,a+n);
queue<int> que;
que.push(a[0]);
mp[a[0]] = 1;
int j = 1;
for(int i = 1; i < n; i++)
{
if(a[i]-que.front()-1 >= d) {que.push(a[i]);mp[a[i]] = mp[que.front()];que.pop();}
else {que.push(a[i]);mp[a[i]] = ++j;}
}
printf("%d\n",j);
for(int i = 0; i < n; i++)
printf("%d%c",mp[b[i]], i == n-1 ? '\n' : ' ');
return 0;
}
D. Glider
分别维护一下有风的前缀和和没风的前缀和,然后对于每个有风的点对前缀和用lower_bound;
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 2e5+100;
vector<int> g[maxn];
map<int,int> mp;
int a[maxn];
int b[maxn];
LL sa[maxn];
LL sb[maxn];
int main()
{
int n,h;
scanf("%d%d",&n,&h);
int x = 0;
a[0] = 0;
b[0] = 0;
sa[0] = 0;
sb[0] = 0;
for(int i = 1; i <= n; i++)
{
int l,r;
scanf("%d%d",&l,&r);
a[i] = r-l;
b[i] = l-x,x = r;
sa[i] = sa[i-1] + a[i];
sb[i] = sb[i-1] + b[i];
//cout << a[i] << " " << b[i] <<" " << sa[i] << " "<<sb[i] << endl;
}
LL ans = 0;
for(int i = 1; i <= n; i++)
{
int idx = lower_bound(sb,sb+n+1,sb[i]+h) - sb - 1;
// cout << sb[i] + h << " "<<idx <<endl;
ans = max(ans,h+sa[idx]-sa[i-1]);
}
printf("%lld\n",ans);
return 0;
}
E. Tree Reconstruction
树的的构造题,首先我们可以发现n肯定会出现在任何一组里,所以我们以n为根节点进行构造,其他出现过的节点分别作为n的一个子树,记录其他1-n-1分别出现的次数,然后可以发现i节点所在的分支,该分支上的节点数一定会等于i在输入数据中出现的次数。所以我们可以判断,如果n未出现n-1次,为NO,然后贪心,从最大出现的i的子树来开始构造,从大到小将未出现的节点放入该子树,只能放(i出现次数-1)个,如果发现一个放入的节点比i 大,则贪心失败,为NO;如果放完了所有为出现的节点,则贪心成功。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1000+10;
const int INF = 0x3f3f3f3f;
typedef pair <LL,int> P;
int n,m,d;
int a[maxn],b[maxn];
vector<int> g1,g2;
vector<int> g3[maxn];
int main()
{
int n;
scanf("%d",&n);
memset(b,0,sizeof(b));
for(int i = 1; i < n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
b[u]++;
b[v]++;
}
if(b[n] != n-1) {printf("NO\n");return 0;}
for(int i = 1; i <= n; i++)
if(b[i] == 0) g1.push_back(i);
else g2.push_back(i);
int j = g2.size()-2;
//cout << b[3] << endl;
for(int i = g1.size()-1; i >= 0; i--)
{
while(j >= 0)
{
if(g1[i] < g2[j] && b[g2[j]] > 1)
{
//cout << g2[j] << endl;
g3[g2[j]].push_back(g1[i]);
b[g2[j]]--;
break;
}
else if(g1[i] > g2[j]) {printf("NO\n");return 0;}
else j--;
}
}
for(int i = 0; i < g2.size()-1; i++) g3[g2[i]].push_back(g2[i]);
printf("YES\n");
//cout << g3[3].size() << endl;
for(int i = 0; i < g2.size()-1; i++)
{
int k = n;
for(int j = 0; j < g3[g2[i]].size(); j++)
{
printf("%d %d\n",k, g3[g2[i]][j]);
k = g3[g2[i]][j];
}
}
return 0;
}
F. Ray in the tube
赛后补题,思考了一下这道题,首先由于对称性,和y没有关系,且步长不能为1,然后发现:
步长为2的会覆盖步长为6,10,14,18。。。。的情况,
步长为4的会覆盖步长为12,20,28,36。。。的情况,
然后我就无法思考了,而且对每个步长还好平移(步长-1)次,然后就不会了gg
其实我已经快做出来了,还是太菜~ 看题解后
我们可以发现所以所有数都可以表示为 和 (i,p 为整数),然后诚如我所发现的,的会覆盖掉情况,所以我们只要枚举步长为 (i <= 29) 就好了,然后对于每次枚举,用map记录上下点对mod = (因为i 从0开始)的余数的次数,然后不需要平移(步长-1)次,只要将上下点的余数都考虑一遍就好了。记录最大值为答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair <LL,int> P;
int n,m,y;
int a[maxn];
int b[maxn];
int p[31];
map<int,int> mp1,mp2;
int main()
{
scanf("%d%d",&n,&y);
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
scanf("%d%d",&m,&y);
for(int i = 0; i < m; i++)
scanf("%d",&b[i]);
p[0] = 1;
for(int i = 1; i <= 30; i++)
p[i] = (p[i-1] << 1);
int ans = 2;
for(int i = 0; i <= 29; i++)
{
mp1.clear();
mp2.clear();
int mod = p[i+1];
for(int j = 0; j < n; j++)
mp1[a[j]%mod]++;
for(int j = 0; j < m; j++)
mp2[b[j]%mod]++;
for(int j = 0; j < n; j++)
ans = max(ans,mp1[a[j]%mod] + mp2[(a[j] + p[i])%mod]);
for(int j = 0; j < m; j++)
ans = max(ans,mp2[b[j]%mod] + mp1[(b[j] + p[i])%mod]);
}
printf("%d\n",ans);
return 0;
}