Problem 1: MSWORLD
时间限制:10000MS
内存限制:256000KB
题目描述
Bessie , Farmer John 的优选牛,刚刚获得了一个牛科动物选美比赛的冠军!并得到了“世界奶牛小姐”的头衔。因此,Bessie将进行一场环球农场旅行,共N个农场(2<=N<=50,000),依次传播农场主和奶牛们之间的亲善友好。为了简单起见,世界可以看作一个二维平面,每座农场的位置用二维坐标(x,y)表示,x,y是-10,0000到10,0000的整数。没有两座农场处于同一个位置上。
哪怕Bessie在两个农场间都是走的直线,在某些农场间的距离还是很远,所以她想随身携带一只装满了干草的箱子,这样她在每一段行程都有充足的食物。因为Bessie在她每到达一个农场后都要重新装满她的箱子,她想弄清楚她可能要走的最大距离,以此来决定它必须携带多大的箱子。帮帮Bessie吧!你只要求出任意两点距离的最大值就可以了。
输入
第一行,一个整数,N。第2~N+1行,两个整数X,Y,描述了农场的坐标。
输出
一个整数,最大距离的平方。
输入样例
4
0 0
0 1
1 1
1 0
输出样例
2
样例说明
农场1(0,0)和农场3(1,1)的距离为 2的开方。
说明:
数据范围限制2<=N<=50,000
思路:
这道题我们还须知道一个前置知识:欧式距离。
后知其法,乃可暴力也!
但是校网数据有问题,n=1?那我们就面向数据编程,懂?
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int N = 5e4 + 10;
ll n, x[N], y[N], maxn = -1;
int main()
{
scanf("%lld", &n);
for(ll i = 1; i <= n; i++)
{
scanf("%lld%lld", &x[i], &y[i]);
for(ll j = 1; j < i; j++)
maxn = max(maxn, (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
printf("%lld", maxn);
return 0;
}
Problem 1: SMRTFUN
时间限制:3000MS
内存限制:256000KB
题目描述
“又肥又温顺,又大又笨,他们看起来那么傻,而且也不有趣……”
这些牛想要证明,他们是既有趣,又聪明的。为了这样做,Bessie组织了一个由牛组成的展览。她有N(1<=N<=100)头牛的情况:聪明程度Si(-1000<=Si<=1000)和有趣程度Fi(-1000<=Fi<=1000)。
Bessie必须选择一些牛来参展。牛的总的聪明值TS是所有参展牛的聪明值Si的和,总的有趣值TF是所有参展牛的有趣值Fi的和。Bessie希望能使TS和TF的和最大。但是,她仍然要求TF和TS都大于等于0,因为,如果其中一个小于0的话,对这个展出将是致命的。
所以,请帮助Bessie找到最大的TS和TF的和,而且这两个数都要非负。
输入
第一行,一个整数N,牛的个数。第2~N+1行,两个整数,依次是Si和Fi。
输出
仅一行,所求得的TS和TF的和
输入样例复
5
-5 7
8 -6
6 -3
2 1
-8 -5
输出样例
8
样例说明
选择第1,3和4号牛。TS=-5+6+2=3,TF=7-3+1=5,所以,TS+TF=3+5=8。虽然,加上2号牛可以使总和变成10,但是,TF小于0,不符合要求。
说明
数据范围限制
1 < = N < = 100 1<=N<=100 1<=N<=100
( − 1000 < = S i < = 1000 ) (-1000<=Si<=1000) (−1000<=Si<=1000)
( − 1000 < = F i < = 1000 ) (-1000<=Fi<=1000) (−1000<=Fi<=1000)
思路:
这道题我们可以把它理解成一道01背包的变式,
把S[i]看成物品重量,F[i]看成物品价值,去做背包。
那背包的容量也就出来的了,想一想,S[i]为重量,
题目S[i]给出最大为1000,N最大为100,那容量就为:
∑ i = 1 n s [ i ] \sum\limits _{i=1}^ns[i] i=1∑ns[i],简单点就是100000(M)
再考虑S[i]可能为负数的情况,那不就是将所有S[i]
都加个M?(超级加倍)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1e2 + 10;
const int M = 1e5;
int n, S[N], F[N], f[N][M * 2 + 10], maxn;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d%d", &S[i], &F[i]);
memset(f, -0x3f, sizeof(f));
f[0][M] = 0;
for(int i = 1; i <= n; i++)
for(int j = M + M; j >= S[i]; j--)
f[i][j] = max(f[i - 1][j], f[i - 1][j - S[i]] + F[i]);
for(int j = M; j <= M * 2; j++)
if(f[n][j] >= 0) maxn = max(maxn, f[n][j] + j - M);
printf("%d\n", maxn);
return 0;
}
Problem 3: 区间和的和
思路:
怎么说,就是一道找规律。
考虑一个数a(位置为i),他在子集和中出现了多少次,
不就算出他前面有多少个数(i),
算出他后面有多少个数(n-i+1),
再根据乘法原理,两数相乘
a n s = ( a n s % M o d + a ∗ ( i ∗ ( n − i + 1 ) ) % M o d ) % M o d ; ans = (ans \% Mod + a * (i * (n - i + 1)) \% Mod) \% Mod; ans=(ans%Mod+a∗(i∗(n−i+1))%Mod)%Mod;
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int Mod=1e9+7;
ll n, a, ans;
int main() {
scanf("%lld", &n);
for (ll i = 1; i <= n; i++)
scanf("%lld", &a),
ans = (ans % Mod + a * (i * (n - i + 1)) % Mod) % Mod;
printf("%lld", ans % Mod);
return 0;
}
Problem 4: 最大异域和
思路:
让 x o r xor xor值更大,肯定最好能保证两个数每一个位(二进制位)都不一样,也就是1的位置要不一样
比如: 1001 x o r 0110 = 1111 , 1001 x o r 1000 = 0001 1001 xor 0110 = 1111, 1001 xor 1000 = 0001 1001xor0110=1111,1001xor1000=0001
预 处 理 出 22 2 0 − > 20 − > 20 − > 2 3 03030 预处理出2 22 ^ 0 − > 2 0 - > 20−>2 ^ 30 3030 预处理出2220−>20−>20−>2303030
对于每一个数,尽量选用大一些的二次方,且不可以重复使用一个二次方
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int N = 2e2 + 10;
const int M = 5e1 + 10;
ll n, ans, a[N], mi[M];
int main()
{
scanf("%lld", &n);
mi[0] = 1;
for(ll i = 1; i <= 30; i++) mi[i] = mi[i - 1] * 2;
for(ll i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
ll tot = 0;
for(int j = 30; j >= 0; j--)
if(tot + mi[j] <= a[i] && mi[j]) tot += mi[j], mi[j] = 0;
ans += tot;
}
printf("%lld\n", ans);
}
Problem 5: 小B浇花
思路:
这道题我们可以贪心。
从低到高枚举花,如果此高度的花不止一朵,
就浇花到此高度的花只剩一朵,一直这样下去。
再在浇花时判断高度上限是否到顶了,
是的话就,用一遍高斯就没了。
#include <cstdio>
#include <iostream>
using namespace std;
const int N=4e4+10;
int n, a, t[N], ans;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a), t[a]++;
for(int i = 0; i <= 40000; i++)
{
if(t[i] > 1)
{
ans += t[i] - 1;
t[i + 1] += t[i] - 1;
if(i == 40000) ans = ans + t[i] * (t[i] - 1);
}
}
printf("%d\n", ans);
return 0;
}
Problem 6: POPULAR
题目描述
每头牛都有一个梦想:成为一个群体中最受欢迎的名牛!在一个有N(1<=N<=10,000)头牛的牛群中,给你M(1<=M<=50,000)个二元组(A,B),表示A认为B是受欢迎的。既然受欢迎是可传递的,那么如果A认为B受欢迎,B又认为C受欢迎,则A也会认为C是受欢迎的,哪怕这不是十分明确的规定。你的任务是计算被所有其它的牛都喜欢的牛的个数。
输入
第一行,两个数,N和M。第2~M+1行,每行两个数,A和B,表示A认为B是受欢迎的。
输出
一个数,被其他所有奶牛认为受欢迎的奶牛头数。
输入样例
3 3
1 2
2 1
2 3
输出样例
1
样例说明
3号奶牛是唯一被所有其他奶牛认为有名的。
说明
数据范围限制
1 < = N < = 10 , 000 ; 1<=N<=10,000; 1<=N<=10,000;
1 < = M < = 50 , 000 1<=M<=50,000 1<=M<=50,000
思路:
这道题就是一道d f s dfsdfs。
我们用邻接表储存之后,
就从每一个点开始dfs,
给每一个它喜欢的点标记。
最后我们看看有多少个点有被标记n − 1次,
那些点就是其他的牛都喜欢的牛。
最后,我们只要输出这样的点的数量,就可以了。
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 5e4 + 10;
struct node {
int x, y, next;} edge[N];
int n, m, u, v, tot, hd[N], count[N], ans;
bool vis[N];
void add(int u, int v) {
edge[++tot] = (node){
u, v, hd[u]}, hd[u]=tot;}
void dfs(int u) {
vis[u] = 1;
for (int i = hd[u]; i; i = edge[i].next)
{
int v = edge[i].y;
if (!vis[v]) count[v]++, dfs(v);
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) scanf("%d%d", &u, &v), add(u, v);
for (int i = 1; i <= n; i++) memset(vis, 0, sizeof(vis)), dfs(i);
for (int i = 1; i <= n; i++)
if (count[i] == n - 1) ans++;
printf("%d", ans);
return 0;
}