链接:https://ac.nowcoder.com/acm/contest/3003#question link
来源:牛客竞赛
牛牛和 牛可乐进行了多轮游戏, 牛牛总共出了 A 次石头,B 次剪刀,C 次布;牛可乐总共出了 X 次石头,Y 次剪刀,Z 次布。 你需要求出 牛牛最多获胜多少局。
第一行,三个非负整数 A , B , C A,B,C A,B,C 。
第二行,三个非负整数 X , Y , Z X,Y,Z X,Y,Z 。
保证 A + B + C = X + Y + Z A+B+C=X+Y+Z A+B+C=X+Y+Z, 0 0 0≤ A , B , C , X , Y , Z A,B,C,X,Y,Z A,B,C,X,Y,Z≤ 1 0 9 10^9 109
贪心即可
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
ll a,b,c,x,y,z;
int main(){
scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&x,&y,&z);
printf("%lld\n",min(a,y)+min(b,z)+min(c,x));
}//Accepted!
牛可乐得到了一个纯数字的字符串 S S S,他想知道在可以任意打乱 S S S 顺序的情况下,最多有多少个不同的子串为 616 616 616 。
第一行,一个正整数 ∣ S ∣ |S| ∣S∣,表示 S S S的长度
第二行,一个字符串 S S S,其字符集为{0,1,2,3,4,5,6,7,8,9}。
保证 1 ≤ ∣ S ∣ ≤ 2 × 1 0 5 1≤∣S∣≤2×10^5 1≤∣S∣≤2×105
贪心,即将所有的 1 , 6 1,6 1,6排成 6161616... 6161616... 6161616...即可
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
int len;char s[maxm];
int one , six;
int main(){
scanf("%d",&len);
scanf("%s",s+1);
rep(i,1,len){
if(s[i] == '1') one++;
if(s[i] == '6') six++;
}
six--;
printf("%d",min(one,six) >= 0 ? min(one,six) : 0);
}//Accepted!
牛牛刚刚考完了期末,尽管 牛牛 做答了所有 n n n 道题目,但他不知道有多少题是正确的。
不过,牛牛 知道第 i i i 道题的正确率是 p i p_i pi。
牛牛 想知道这 n n n 题里恰好有 0 , 1 , … , n 0,1,…,n 0,1,…,n 题正确的概率分别是多少,对 1 0 9 + 7 10^9+7 109+7 取模。
第一行,一个正整数 n n n 。
第二行, n n n 个整数 p 1 , p 2 , … , p n p_1,p_2,…,p_n p1,p2,…,pn,在模 1 0 9 + 7 10^9+7 109+7 意义下给出。
保证 1 ≤ n ≤ 2000 1≤n≤2000 1≤n≤2000。
我们记从 p 1 , p 2 , . . . , p n p_1,p_2,...,p_n p1,p2,...,pn中取出 k k k个相乘,这样所有的组合之和为 P k P_k Pk。我们会发现这 n n n个题中恰好 k k k个题对的概率是 P k − C k + 1 k ∗ P k + 1 + . . . + ( − 1 ) n − k ∗ C n k ∗ P n P_k -C_{k+1}^k*P_{k+1}+...+(-1)^{n-k}*C_n^k*P_n Pk−Ck+1k∗Pk+1+...+(−1)n−k∗Cnk∗Pn。于是问题转换为求解 P k P_k Pk与 C n k C_n^k Cnk。我们很自然的有递推式 C n k = C n − 1 k − 1 + C n − 1 k C_n^k=C_{n-1}^{k-1}+C_{n-1}^k Cnk=Cn−1k−1+Cn−1k以及 P ( n , k ) = P ( n − 1 , k ) + p i ∗ P ( n − 1 , k − 1 ) P(n,k) = P(n-1,k)+p_i*P(n-1,k-1) P(n,k)=P(n−1,k)+pi∗P(n−1,k−1)。(其中 P ( m , k ) P(m,k) P(m,k)表示的意思是从 p 1 , p 2 , . . . , p m p_1,p_2,...,p_m p1,p2,...,pm中取出 k k k个相乘,这样所有的组合之和)
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define maxn 100005
#define maxm 400005
#define mod 1000000007
ll p[maxn] ;
int n;
ll P[2005][2005];
ll c[2005][2005];
void get(){
c[0][0] = 1;
c[1][0] = 1, c[1][1] = 1;
rep(i,2,2000){
c[i][0] = 1;
c[i][i] = 1;
rep(j,1,i-1) c[i][j] = (c[i-1][j-1] + c[i-1][j])%mod;
}
P[0][0] = 1;
rep(i,1,2000){
P[i][0] = 1;
P[i][i] = (P[i-1][i-1]*p[i])%mod;
rep(j,1,i-1) P[i][j] = (P[i-1][j] +p[i]*P[i-1][j-1]%mod)%mod;
}}
int main(){
scanf("%d",&n);
rep(i,1,n) scanf("%lld",&p[i]);
get();
rep(i,0,n){
ll ans = 0;
int sign = 1;
rep(j,i,n){
ans = (ans + c[j][j-i]*P[n][j]*sign)%mod;
sign = sign*(-1);
}
if(ans < 0) ans += mod;
printf("%lld ",ans);}
}//Accepted!
给 n n n个不重合的点,问这些点构成的三角形中有多少个钝角三角形
第一行,一个正整数 n n n,表示点数。
第二行至第 n + 1 n+1 n+1 行中,第 i + 1 i+1 i+1 行包含两个整数 x i x_i xi, y i y_i yi,表示第 i i i 个点的坐标。
保证 1 ≤ n ≤ 500 1\leq n\leq 500 1≤n≤500, − 1 0 4 ≤ x i , y i ≤ 1 0 4 -10^4\leq x_i,y_i\leq 10^4 −104≤xi,yi≤104,任意两点不重合。
水题,枚举所有三角形,点乘判断钝角即可
#include
#include
#define maxn 501
using namespace std;
int n;
struct Point{
int x,y;
inline Point(int x=0,int y=0):x(x),y(y){}
}p[maxn];
Point operator + (Point A,Point B){
return Point(A.x+B.x,A.y+B.y);
}
Point operator - (Point A,Point B){
return Point(A.x-B.x,A.y-B.y);
}
int operator * (Point A,Point B){
return A.x*B.x+A.y*B.y;
}
int Cross(Point A,Point B) // 计算叉积
{
return A.x*B.y-A.y*B.x;
}
int ans;
int check(int i,int j,int k){
if((p[i]-p[j])*(p[k]-p[j])<0&&Cross(p[i]-p[j],p[k]-p[j])!=0)return 1;
if((p[i]-p[k])*(p[j]-p[k])<0&&Cross(p[i]-p[k],p[j]-p[k])!=0)return 1;
if((p[j]-p[i])*(p[k]-p[i])<0&&Cross(p[j]-p[i],p[k]-p[i])!=0)return 1;
return 0;
}
int main(){
scanf("%d",&n);
int a,b;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
p[i]=Point(a,b);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=j+1;k<=n;k++){
ans+=check(i,j,k);
}
}
}
printf("%d",ans);
return 0;
}
给定n,求有多少个不同的正整数三元组 ( i , j , k ) \text{}(i,j,k) (i,j,k)满足 i + j = k \sqrt i+\sqrt j=\sqrt k i+j=k,且 i × j ≤ n i\times j\leq n i×j≤n
当两个三元组 ( i 1 , j 1 , k 1 ) \text{}(i_1,j_1,k_1) (i1,j1,k1), 满足 i 1 ≠ i 2 i_1\neq i_2 i1=i2 或 j 1 ≠ j 2 j_1\neq j_2 j1=j2 或 k 1 ≠ k 2 k_1\neq k_2 k1=k2 时它们被认为是不同的。
第一行,一个正整数 n n n。
保证 1 ≤ n ≤ 4 × 1 0 7 1\leq n\leq 4\times 10^7 1≤n≤4×107
确定 i i i和 j j j即可确定 k k k,且 k k k为整数,容易发现当左边的式子为 a x + b x a\sqrt x +b\sqrt x ax+bx时有这样的整数 k k k
于是我们枚举 x x x,计算二元组 ( a , b ) (a,b) (a,b)的个数
注意到诸如 8 \sqrt 8 8在枚举 x = 2 x=2 x=2时已经计算过,所以为了避免重复,我们枚举的 x x x不能是完全平方数的倍数,可以预处理掉
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define mst(s) memset(s,0,sizeof(s))
#define ls(x) x<<1
#define rs(x) x<<1|1
#define lb(x) x&-x
#define pii pair
#define pli pair
#define pll pair
#define pi acos(-1)
#define F first
#define S second
#define cuts printf("\n--------------\n");
#define maxn 40000001
#define maxm 400005
int n, m,p, ans = 0;
int vis[maxn];
int main(){
scanf("%d",&n);
m=(int)sqrt(n);
for(int i=2;i<=m;i++){
int j=1,k=i*i;
while(k*j<=n){
vis[k*j]=1;
j++;
}
}
rep(i,1,m){
if(vis[i]==1)continue;
rep(j,1,m/i)ans+=(m/i)/j;
}
printf("%d",ans);
}
链接:https://ac.nowcoder.com/acm/contest/3003/F
来源:牛客网
牛牛和 牛可乐 面前有 n 个物品,这些物品编号为 1 , 2 , … … , n 1,2,……,n 1,2,……,n,每个物品有两个属性 a a a i i i, b b b i i i。
牛牛与 牛可乐会轮流从剩下物品中任意拿走一个, 牛牛先选取。
设 牛牛选取的物品编号集合为 H H H,牛可乐选取的物品编号的集合为 T T T,取完之后,牛牛 得分为 Σ \Sigma Σ i ∈ H i\in\mathbb H i∈H a a a i i i;而 牛可乐得分为 Σ \Sigma Σ i ∈ T i\in\mathbb T i∈T b b b i i i。
牛牛和 牛可乐都希望自己的得分尽量比对方大(即最大化自己与对方得分的差)。
你需要求出两人都使用最优策略的情况下,最终分别会选择哪些物品,若有多种答案或输出顺序,输出任意一种。
a a a i i i与 b b b i i i之和从大到小排序,轮流从大到小取。
//
// main.cpp
// cpp
//
// Created by ZhuChenyu on 2019/11/08.
// Copyright 2019年 ZhuChenyu. All rights reserved.
//
#include
#include
#include
#include
#include
#define MOD 1000007
#define maxn 200020
#define INF 2147483647
typedef unsigned float_bits;
using namespace std;
//priority_queue ,greater > que;
struct wayy
{
int num,m;
}c[maxn];
int n;
int a[maxn]={0},b[maxn]={0};
int cmp(struct wayy x,struct wayy y)
{
if (x.m>y.m) return 1; else return 0;
}
int main()
{
int i,j;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for (i=1;i<=n;i++)
{
scanf("%d",&b[i]);
}
for (i=1;i<=n;i++)
{
c[i].m=a[i]+b[i];
c[i].num=i;
}
sort(c+1,c+n+1,cmp);
/*for (i=1;i<=n;i++)
{
printf("%d %d\n",c[i].num,c[i].m);
}*/
for (i=1;i<=n;i++)
{
if (i%2==1) printf("%d ",c[i].num);
}
printf("\n");
for (i=1;i<=n;i++)
{
if (i%2==0) printf("%d ",c[i].num);
}
printf("\n");
return 0;
}
/*3
7 6 8
4 2 5*/
牛可乐有七个整数 $a,b,c,d,e,f,g $并且他猜想 a d + b e + c f = g a^d+b^e+c^f=g ad+be+cf=g。但牛可乐无法进行如此庞大的计算。
请验证 牛可乐的猜想是否成立。
第一行一个正整数 T T T,表示有 T T T 组数据。
每组数据输入一行七个整数 a , b , c , d , e , f , g a,b,c,d,e,f,g a,b,c,d,e,f,g 。
保证 1 ≤ T ≤ 1000 1≤T≤1000 1≤T≤1000, − 1 0 9 ≤ a , b , c , g ≤ 1 0 9 −10^9 ≤a,b,c,g≤10^9 −109≤a,b,c,g≤109, 0 ≤ d , e , f ≤ 1 0 9 0≤d,e,f≤10^9 0≤d,e,f≤109 保证不会出现指数和底数同为 0 的情况。
哈希即可
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
ll a, b, c ,d ,e ,f, g;
const int mod[100]={2,3,5,7,11,13,23,29,31,37,41,43,59,61,67,71,73,79,97,101,103,107,109,113,137,139,149,151,157,163,163,179,181,191,193,197,199,227,229,233,239,241,251,269,271,277,281,283,293,313,317,331,337,347,349,367,373,379,383,389,397};
ll ksm(ll s,ll x,ll p){
ll res = 1;
while(x){
if(x&1) res = res*s%p;
x >>= 1;
s = s*s%p;
}
return res;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g);
int ok = 1;
rep(i,0,59){
if((((ksm(a,d,mod[i]) + ksm(b,e,mod[i]) + ksm(c,f,mod[i])) % mod[i]) + mod[i])%mod[i] != ((g%mod[i]) + mod[i])%mod[i]){
ok = 0;
break;
}
}
if(ok) printf("Yes\n");
else printf("No\n");
}
}//Accepted!
给定 n n n个元素,第 i i i个元素的值为 a i a_i ai,从中多次选择至少 k k k个元素,费用是这些元素中的最大值减去最小值,保证每个元素都被选择且仅被选择一次,求最小费用
第一行两个正整数 n , k n, k n,k。
第二行 n n n 个整数 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an
保证 1 ≤ k ≤ n ≤ 3 × 1 0 5 1\leq k\leq n\leq 3\times 10^5 1≤k≤n≤3×105 , 0 ≤ a i ≤ 1 0 9 0\leq a_i\leq 10^9 0≤ai≤109。
显然应该先排序,每次选择的元素都是连续的可以保证最小,并且选择次数尽可能地多才可能达到费用最小。
反向考虑,对排好序的数列切 m m m刀,刀与刀之间的距离至少为 k k k,在 a j , a j + 1 a_j,a_{j+1} aj,aj+1之间切一刀可以使总费用减少 a j + 1 − a j a_{j+1}-a_j aj+1−aj,显然 d p dp dp可做
转移方程式为
f [ i ] = m a x j ∈ [ 1 , i − k ] { f [ j ] } + b [ i ] f[i]=max_{j\in [1,i-k]}\{f[j]\}+b[i] f[i]=maxj∈[1,i−k]{f[j]}+b[i]
f [ i ] f[i] f[i]表示最后一刀切在 i i i处的最大减少费用, b [ i ] b[i] b[i]表示差值
其中最大值的计算可以在转移过程中不断更新,时间复杂度 O ( n ) O(n) O(n)
#include
#include
#define maxn 300001
using namespace std;
int a[maxn],b[maxn];
int f[maxn];
int ans,n,k,now;
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
ans=a[n]-a[1];
for(int i=1;i<=n-1;i++){
b[i]=a[i+1]-a[i];
}
int front=0;
for(int i=k;i<=n-k;i++){
front=max(front,f[i-k]);
f[i]=front+b[i];
now=max(now,f[i]);
}
printf("%d",ans-now);
}
给定 n n n个带权节点,权值为 v v v,点 i i i与点 j j j之间建边的费用为 l o w b i t ( v i ⊕ v j ) lowbit(v_i \oplus v_j) lowbit(vi⊕vj),求使这 n n n个点互相连通的最小花费
第一行,一个正整数 n n n 。
第二行, n n n 个非负整数 v 1 , v 2 , … , v n v_1,v_2,\dots,v_n v1,v2,…,vn
保证 1 ≤ n ≤ 2 × 1 0 5 1\leq n\leq 2\times 10^5 1≤n≤2×105 , 0 ≤ v i < 2 30 0\leq v_i < 2^{30} 0≤vi<230
乍一看类似gcd最小生成树,其实是智商题,我们对所有的二进制 v v v从最后一位往前扫,找到第一个既有0又有1的位,将0和1相连,连接 n − 1 n-1 n−1条边,答案就是此时的边权 × ( n − 1 ) \times (n-1) ×(n−1)
但对于相同的数,显然相同的数相连的边权的0是最小的,所以加个去重操作就好了
#include
#include
#include
#define ll long long
#define maxn 200005
using namespace std;
int n;
ll v;
int f[40][5];
int zn;
ll ans;
ll x[maxn];
int main(){
scanf("%d",&n);
ans=n-1;
for(int i=1;i<=n;i++){
scanf("%lld",&v);
x[i]=v;
int p=1;
while(v>0){
f[p][v&1]=1;
p++;
v>>=1;
}
for(int i=p;i<=30;i++){
f[i][0]=1;
}
}
sort(x+1,x+n+1);
for(int i=2;i<=n;i++){
if(x[i]==x[i-1])ans--;
}
for(int i=1;i<=30;i++){
if(f[i][0]==1&&f[i][1]==1){
printf("%lld",ans);
return 0;
}
ans=ans*2;
}
printf("0");
return 0;
}
牛可乐有 n n n 个一次函数,第 i i i 个函数为 f i ( x ) = k i ∗ x + b i f_i(x)=k_i * x+b_i fi(x)=ki∗x+bi 。 牛可乐有 m m m 次操作,每次操作为以下二者其一:
• 1 i k b 将 f i ( x ) f_i(x) fi(x) 修改为 f i ( x ) = k × x + b f_i(x)=k×x+b fi(x)=k×x+b。
• 2 l r 求 f r ( f r − 1 ( ⋯ ( f l + 1 ( f l ( 1 ) ) ) ⋯ ) ) f_r(f_{r−1}(⋯(f_{l+1}(f_l(1)))⋯ )) fr(fr−1(⋯(fl+1(fl(1)))⋯ ))。
牛可乐当然(bu)会做啦,他想考考你——
答案对 1 0 9 + 7 10^9+7 109+7 取模。
第一行,两个正整数 n , m n,m n,m 。
第二行, n n n 个整数 k 1 , k 2 , … , k n k_1,k_2,…,k_n k1,k2,…,kn 。
第三行, n n n 个整数 b 1 , b 2 , … , b n b_1,b_2,…,b_n b1,b2,…,bn。
接下来 m m m 行,每行一个操作,格式见上。
保证 1 ≤ n , m ≤ 2 × 1 0 5 1≤n,m≤2×10^5 1≤n,m≤2×105
可以观察到要求的式子为 k l ∗ k l + 1 ∗ . . . ∗ k r + k r ∗ k r − 1 ∗ . . . k l + 1 ∗ b l + . . . + b r k_l*k_{l+1}*...*k_r+k_r*k_{r-1}*...k_{l+1}*b_l+...+b_r kl∗kl+1∗...∗kr+kr∗kr−1∗...kl+1∗bl+...+br。我们维护分别维护 k l ∗ k l + 1 ∗ . . . ∗ k r k_l*k_{l+1}*...*k_r kl∗kl+1∗...∗kr与 k r ∗ k r − 1 ∗ . . . k l + 1 ∗ b l + . . . + b r k_r*k_{r-1}*...k_{l+1}*b_l+...+b_r kr∗kr−1∗...kl+1∗bl+...+br。直接使用线段树单点修改,区间查询即可。
#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define ls(x) x<<1
#define rs(x) ((x<<1)|1)
#define maxn 210000
const int mod = 1e9 + 7;
int n , m , l[maxn<<2],r[maxn<<2],mid[maxn<<2],l1,r1;
ll k[maxn], b[maxn], f[maxn<<2], g[maxn<<2], k0, b0, ansf, ansg;
void up(int x){
f[x] = (f[ls(x)]*f[rs(x)])%mod;
g[x] = (g[ls(x)]*f[rs(x)] + g[rs(x)])%mod;
}
void build(int x,int l0,int r0){
l[x] = l0;
r[x] = r0;
if(l0 == r0){
f[x] = k[l0];
g[x] = b[l0];
return;
}
mid[x] = (l[x] + r[x]) >> 1;
build(ls(x),l[x],mid[x]);
build(rs(x),mid[x]+1,r[x]);
up(x);} void update(int x){
if(l[x] == r[x]){
f[x] = k0;
g[x] = b0;
return;
}
if(l1 <= mid[x]) update(ls(x));
else update(rs(x));
up(x);
}
void query(int x){
if(l1 <= l[x] && r[x] <= r1){
ansf = ansf*f[x] % mod;
ansg = (ansg * f[x] + g[x])%mod;
return;
}
if(l1 <= mid[x]) query(ls(x));
if(r1 > mid[x]) query(rs(x));}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%lld",&k[i]);
rep(i,1,n) scanf("%lld",&b[i]);
build(1,1,n);
while(m--){
int op;
scanf("%d",&op);
if(op == 1){
scanf("%d%lld%lld",&l1,&k0,&b0);
update(1);
}
else{
scanf("%d%d",&l1,&r1);
ansf = 1;
ansg = 0;
query(1);
printf("%lld\n",(ansf+ansg)%mod);
}
}return 0;
}//Accepted!