有 n n n只斑羚,每只斑羚跳跃的最远距离为 x [ i ] x[i] x[i],斑羚在别人的背上起跳的最远距离为 y [ i ] y[i] y[i],峡谷的两岸的距离为 s s s,问在最好情况下,有几只斑羚可以用别人的背当跳板跳到对岸,但由于斑羚的先天原因(主要是太肥),只能把别人当跳板一次
s < = 1000000000 ; x [ i ] , y [ i ] < = s ; 不 保 证 x [ i ] < y [ i ] s<=1000000000; x[i],y[i]<=s; 不保证x[i]<y[i] s<=1000000000;x[i],y[i]<=s;不保证x[i]<y[i]
分类讨论
x i > = s x_i>=s xi>=s,答案+1,然后不管了
x i + y i > = s x_i+y_i>=s xi+yi>=s,有可能做贡献,用数组 a i a_i ai存起来
x i + y i < s x_i+y_i<s xi+yi<s,不可能做贡献,给别人当跳板,将 x i x_i xi用个 m u l t i s e t multiset multiset存起来
将 a i a_i ai按x升序排序,x相同时y降序排列
枚举 a i a_i ai,判断 m u l t i s e t multiset multiset是否存在 > = s − a i , y >=s-a_{i,y} >=s−ai,y的数,有的时候取最小,然后贡献+1,将对应的数从 m u l t i s e t multiset multiset中删去
m u l t i s e t multiset multiset不存在时则将 a i , x a_{i,x} ai,x给别人当跳板
#include
#include
#include
#include
#include
#include
#include
#define N 1000005
using namespace std;
struct Node { int x, y; }c[N];
int n, s, cnt, ans;
multiset cdp;
bool cmp(Node aa, Node bb)
{
if (aa.x == bb.x) return aa.y > bb.y;
return aa.x < bb.x;
}
int main()
{
scanf("%d %d", &n, &s);
int a, b;
for (int i = 1; i <= n; i++)
{
scanf("%d %d", &a, &b);
if (a >= s) ++ans;
else if (a + b >= s) c[++cnt].x = a, c[cnt].y = b;
else cdp.insert(a);
}
sort(c + 1, c + cnt + 1, cmp);
for (int i = 1; i <= cnt; i++)
{
multiset ::iterator num = cdp.lower_bound(s - c[i].y);
if (num == cdp.end()) cdp.insert(c[cnt].x); else ++ans, cdp.erase(num);
}
printf("%d\n", ans);
return 0;
}
给出 T T T个询问,每个询问给出一个数n,问n的因子个数。
1 ≤ n , T ≤ 1 0 4 1≤n,T≤10^4 1≤n,T≤104
暴力就完事了
#include
using namespace std;
int T, n;
int main()
{
scanf("%d", &T);
for (; T; T--)
{
scanf("%d", &n);
int num = 0;
for (int i = 1; i * i <= n; i++)
if (n % i == 0)
{
num++;
if (i * i != n) num++;
}
printf("%d\n", num);
}
return 0;
}
小T一开始有一张一共有n个字符串的字符串表,
现在他进行以下操作Q次:
(1):给字符串表中加入一个字符串s。
(2):给字符串表去重,输出去掉字符串的数量。
1 ≤ n , Q ≤ 5 × 1 0 5 1≤n,Q≤5×10^5 1≤n,Q≤5×105
对于所有输入的字符串长度<=40
用set存,每次遇到相同的累加一下,回答询问的时候直接输出然后清零继续下一次统计
这题特别有毛病。你的指令判断 0 / 1 0/1 0/1不用%d必WA。。
#include
#define N 1000005
using namespace std;
set s;
string aa;
int n, m, cnt, opt;
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
{
cin >> aa;
if (s.count(aa) == 1) cnt++; else s.insert(aa);
}
while (m--)
{
scanf("%d", &opt);
if (opt == 1)
{
cin >> aa;
if (s.count(aa) == 1) cnt++; else s.insert(aa);
}
else
{
printf("%d\n", cnt);
cnt = 0;
}
}
return 0;
}
两个分数x1/y1, x2/y2,求他们的和差积商
1 ≤ x 1 , y 1 , x 2 , y 2 ≤ 1 0 5 1≤x1,y1,x2,y2≤10^5 1≤x1,y1,x2,y2≤105
保证答案≤long long且分数有意义。
分别都通分一下然后求个gcd没了
注意一下正负性
#include
using namespace std;
typedef long long ll;
ll gcd(ll aa, ll bb)
{
return bb ? gcd(bb, aa % bb) : aa;
}
ll ax, ay, bx, by;
ll xx, yy, zz;
int main()
{
scanf("%lld %lld %lld %lld", &ax, &ay, &bx, &by);
xx = ax * by + bx * ay;
yy = ay * by;
if (xx < 0 && yy > 0) printf("-");
if (xx > 0 && yy < 0) printf("-");
xx = abs(xx); yy = abs(yy);
zz = gcd(xx, yy);
printf("%lld %lld\n", xx / zz, yy / zz);
xx = ax * by - bx * ay;
yy = ay * by;
if (xx == 0) printf("0 0\n");
else {
if (xx < 0 && yy > 0) printf("-");
if (xx > 0 && yy < 0) printf("-");
xx = abs(xx); yy = abs(yy);
zz = gcd(xx, yy);
printf("%lld %lld\n", xx / zz, yy / zz);
}
xx = ax * bx;
yy = ay * by;
if (xx < 0 && yy > 0) printf("-");
if (xx > 0 && yy < 0) printf("-");
xx = abs(xx); yy = abs(yy);
zz = gcd(xx, yy);
printf("%lld %lld\n", xx / zz, yy / zz);
xx = ax * by;
yy = bx * ay;
if (xx < 0 && yy > 0) printf("-");
if (xx > 0 && yy < 0) printf("-");
xx = abs(xx); yy = abs(yy);
zz = gcd(xx, yy);
printf("%lld %lld\n", xx / zz, yy / zz);
return 0;
}
等离子炮有n个操作信号,第i个操作信号的强度为b[i]。总体强度为各操作信号的强度之和。
由于有些信号太弱了了 (强度<0),水宝宝想把它们删除。但是水宝宝自己不会删除信号,所以他找来了同船的队友帮忙。
有 m位队友,第ii 位队友只会删除编号在 L[i] 和 R[i]之间的信号,且每删除一个信号,花费 C[i]格能量。飞船一共有 k格能量,问他在请队友删除完信号后,总体强度最大是多少。
1 ≤ n , m ≤ 1 0 5 ; 1 ≤ k ≤ 500 ; 1 ≤ C [ i ] ≤ 500 ; 1 ≤ L [ i ] ≤ R [ i ] ≤ n ; − 1 0 9 ≤ b [ i ] ≤ 1 0 9 1≤n,m≤10^5;1≤k≤500;1≤C[i]≤500;1≤L[i]≤R[i]≤n;-10^9≤b[i]≤10^9 1≤n,m≤105;1≤k≤500;1≤C[i]≤500;1≤L[i]≤R[i]≤n;−109≤b[i]≤109
总强度 s u m = b 1 + b 2 + . . . + b n − 1 + b n sum=b_1+b_2+...+b_{n-1}+b_n sum=b1+b2+...+bn−1+bn
假如我删了一个 b k b_k bk, b k b_k bk必定要 < 0 <0 <0,那么我们总强度提升了 − b k -b_k −bk
那么我们设 d p i dp_{i} dpi表示花费了 i i i格能量我所能提升的最大强度,
问题转化成01背包,最后答案就是 s u m + m a x ( d p i ) sum+max(dp_i) sum+max(dpi)
对于将一个操作 ( l , r , x ) (l,r,x) (l,r,x),用线段树的很多个结点去表示,
如果结点 o o o所代表的区间 [ l 1 , r 1 ] [l1,r1] [l1,r1]能被包含在 [ l , r ] [l,r] [l,r]内,那么我们就判断更新这个结点记录的值 a o a_{o} ao
a o a_{o} ao就是操作区间 ( l 1 , r 1 ) (l1,r1) (l1,r1)的每一个数,我都可以用代价 a o a_{o} ao删掉,而且 a o a_{o} ao是对 k ∈ [ l , r ] k∈[l,r] k∈[l,r]都通用的最小代价
然后对于一个 b i < 0 b_i<0 bi<0而言,我们删掉它的最小代价,就是所有包含它的区间的 a o a_{o} ao的 m i n min min
时间复杂度就是 O ( n ( l o g n + k ) ) O(n(logn+k)) O(n(logn+k))
#include
#include
#include
#include
#include
#include
#define lson(x) x * 2
#define rson(x) x * 2 + 1
#define inf 0x3f3f3f3f
#define N 100005
#define M 505
using namespace std;
typedef long long ll;
struct Node { int num; }C[N*5];
int a[N], n, k, m, tot, cdp;
ll dp[M], sum;
void Build(int x, int l, int r)
{
C[x].num = inf;
if (l == r) return;
int mid = (l + r) >> 1;
Build(lson(x), l, mid);
Build(rson(x), mid + 1, r);
}
void change(int x, int l, int r, int liml, int limr, int cnum)
{
if (l > limr || r < liml) return;
int mid = (l + r) >> 1;
if (liml <= l && r <= limr) { C[x].num = min(C[x].num, cnum); return; }
change(lson(x), l, mid, liml, limr, cnum);
change(rson(x), mid + 1, r, liml, limr, cnum);
}
void Get_num(int x, int l, int r, int pos)
{
cdp = min(cdp, C[x].num);
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) Get_num(lson(x), l, mid, pos);
else Get_num(rson(x), mid + 1, r, pos);
}
int main()
{
scanf("%d %d %d", &n, &k, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum = (ll)sum + a[i];
Build(1, 1, n);
int l, r, x;
for (int i = 1; i <= m; i++)
{
scanf("%d %d %d", &l, &r, &x);
if (l > r) swap(l, r);
change(1, 1, n, l, r, x);
}
for (int i = 1; i <= k; i++) dp[i] = -inf;
ll maxnum = -inf;
for (int i = 1; i <= n; i++)
if (a[i] < 0)
{
a[i] = -a[i]; cdp = inf; Get_num(1, 1, n, i);
for (int j = k; j >= cdp; j--) dp[j] = max(dp[j], dp[j - cdp] + a[i]), maxnum = max(maxnum, dp[j]);
}
printf("%lld\n", sum + maxnum);
return 0;
}