子段乘积
尺取法就完事熬
#include <iostream> #include <cstring> using namespace std; typedef long long ll; int mod = 998244353; template<typename T> void read(T &x){ x = 0;char ch = getchar();ll f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f; } inline int mul(int x,int y){return 1ll*x*y%mod;} inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;} inline int sub(int x,int y){return x-y<0?x-y+mod:x-y;} inline int sq(int x){return 1ll*x*x%mod;} int pow(int a,int b){return b == 0 ? 1 : ( b&1 ? mul(a,sq(pow(a,b/2))) : sq(pow(a,b/2)));} int n,k,a[1000010]; int main(){ read(n);read(k); for(int i=1;i<=n;i++){ read(a[i]); } int ans = 0,md = 1,cnt = 0; for(int i=1;i<=k;i++){ if(a[i] == 0){ cnt++; }else{ md = mul(md,a[i]); } } for(int i=1;i+k-1<=n;i++){ if(!cnt)ans = max(ans,md); if(a[i] == 0)cnt--; else md = mul(md,pow(a[i],mod-2)); if(a[i+k] == 0)cnt++; else md = mul(md,a[i+k]); } cout<<ans<<endl; return 0; }
子段异或,首先从第一个数开始不断地异或到最后,异或过程中一个值重复出现,就说明这两个值之间出现一段异或起来为0的;
#include <bits/stdc++.h> #define debug(x) cerr<<#x<<'='<<x<<endl #define set0(x) memset(x,0,sizeof(x)) using namespace std; typedef long long ll; typedef pair<ll,ll> pii; template<typename T> void read(T &x){ x = 0;char ch = getchar();ll f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f; } ll n,a[200010],ans = 0; map<ll,int> Mp; int main() { read(n); ll csu = 0; Mp[0] = 1; for(int i=0;i<n;i++){ read(a[i]); csu^=a[i]; ans+=Mp[csu]; Mp[csu]+=1; } cout<<ans<<endl; return 0; }
最小表达式
#include <bits/stdc++.h> using namespace std; typedef long long ll; int cnt[20]; int sum[500050]; char s[500050]; int main() { cin>>s; int ccnt = 1; int n = strlen(s); for(int i=0;i<n;i++){ if(isdigit(s[i])){ cnt[s[i]-'0']+=1; }else{ ccnt+=1; } } int p = 0,cp = 0; for(int i=10;i>=1;i--){ while(cnt[i]){ sum[cp]+=i; cnt[i]-=1; p = (p+1)%ccnt; if(p == 0)cp+=1; } } for(int i=0;i<500010;i++){ sum[i+1]+=sum[i]/10; sum[i]%=10; } int opt = 0; for(int i=500010;i>=0;i--){ if(opt || sum[i]){ cout<<sum[i]; opt = 1; } } cout<<endl; return 0; }
树上博弈
作者:nocriz
链接:https://www.nowcoder.com/discuss/365889
来源:牛客网
首先,注意到输掉的唯一方法是自己的唯一一条边有另一个人,那么自己一定是在叶子上。
令两个人之间的距离为D。请注意,每人行动后D增加1或减少1。 因此,每有人走一步D的奇偶性都会改变。
假设最初,在牛牛移动之前,D是偶数。 那么当牛牛移动时D将始终为偶数,而当牛妹移动时D将始终为奇数。
请注意,只要牛牛和牛妹的令牌位于相邻的节点中,D=1。因此,如果D为偶数,则他们不在相邻的单元格中,并且牛牛始终可以移动。
另一方面,由于牛牛总是可以移动,因此他可以向牛妹的方向移动,将牛妹必然会最终移动到叶子上。同样,如果最初D是奇数,则牛妹获胜。
因此,答案取决于距离的奇偶性:如果是偶数,则牛牛获胜,否则牛妹获胜。
可以发现,只有牛牛的初始位置和牛妹的初始位置距离为偶数时,牛牛获胜。只需要分别求出深度为奇数的点和深度为偶数的点的数量即可。
#include <bits/stdc++.h> #define debug(x) cerr<<#x<<'='<<x<<endl #define set0(x) memset(x,0,sizeof(x)) using namespace std; typedef long long ll; typedef pair<ll,ll> pii; template<typename T> void read(T &x){ x = 0;char ch = getchar();ll f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f; } template<typename T, typename... Args> void read(T &first, Args& ... args) { read(first); read(args...); } int n,q,x,y,depth[1000010]; ll cnt[2]; int main() { read(n); depth[1] = 0; cnt[0] = 1; for(int i=2;i<=n;i++){ int cc; read(cc); depth[i] = depth[cc]^1; cnt[depth[i]]+=1; } cout<<cnt[0]*(cnt[0]-1)+cnt[1]*(cnt[1]-1)<<endl; return 0; }
作者:nocriz
链接:https://www.nowcoder.com/discuss/365889
来源:牛客网
音乐鉴赏
如果随机占比为 xxx ,一个人分数为 scorescorescore ,那么他优秀的概率为 (score−90)(1−x)90x\frac{(score-90)(1-x)}{90x}90x(score−90)(1−x)。
这个概率可以这么计算:首先把分数减90,大于0就优秀,那么就变成(score−90)∗(1−x)−y∗x≥0(score-90)*(1-x)-y*x\ge 0(score−90)∗(1−x)−y∗x≥0,其中y是一个随机的0到90之间的数字。(score−90)∗(1−x)≥y∗x(score-90)*(1-x)\ge y*x(score−90)∗(1−x)≥y∗x,(score−90)∗(1−x)x≥y\frac{(score-90)*(1-x)}{x}\ge yx(score−90)∗(1−x)≥y,这个概率就是上面所写的概率。
E=∑i=1n(scorei−90)(1−x)90x=0.1nE=\sum_{i=1}^{n} \frac{(score_i-90)(1-x)}{90x}=0.1nE=∑i=1n90x(scorei−90)(1−x)=0.1n,解方程可知答案为∑i=1n(scorei−90)9n+∑i=1n(scorei−90)\frac{\sum_{i=1}^n(score_i-90)}{9n+\sum_{i=1}^n(score_i-90)}9n+∑i=1n(scorei−90)∑i=1n(scorei−90)。
也可以使用二分求解。
#include<bits/stdc++.h> using namespace std; int main(){ int n,sum=0,tp=0; cin>>n; for(int i=0;i<n;i++){ cin>>tp; sum+=tp; } double S = sum-90*n; cout<<setprecision(2)<<fixed; cout<<(S/(9*n+S)*100)<<"%\n"; return 0; }
匹配星星
这道题目可以使用贪心算法求解。先按照X坐标从小到大排序,然后对于每一个点
- 如果Z = 1,查询比他X坐标小的Y坐标最大的Z= 0的点,进行配对,如果配对成功则将那个点都从候选点中排除。
- 如果Z = 0,将该点加入候选点。
#include <set> #include <vector> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; struct P{ int a,b,c; bool operator < (const P &rhs) const{ if(a == rhs.a)return c>rhs.c; return a<rhs.a; } }alp[300030]; int n; int main() { cin>>n; for(int i=0;i<n;i++) cin>>alp[i].a>>alp[i].b>>alp[i].c; sort(alp,alp+n); multiset<int> pool; multiset<int>::iterator it; int ans = 0; for(int i=0;i<n;i++){ if(alp[i].c){ it = pool.lower_bound(alp[i].b); if(it!=pool.begin()){ --it; pool.erase(it); ans+=1; } }else{ pool.insert(alp[i].b); } } cout<<ans<<endl; return 0; }
H - 坐火车
线段树写的,我看出题人那个思维我还是不习惯,自己想了一个写法。
先用g统计1到n颜色的总数量,然后gg统计1到i-1的颜色数量,每次都只改变一个点,我们只需要更新这个点的颜色贡献,贡献值为res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c]; 然后查询就好了。这题有点卡常,加了个ll rr就A了
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<string> #define ls k<<1,l,mid #define rs k<<1|1,mid+1,r #define mp(x,y) make_pair(x,y) #define r(x) read(x) #define rrr(x,y,z) read(x);read(y);read(z) #define FOR(i,l,r) for(int i=l;i<=r;i++) using namespace std; typedef long long LL; typedef pair<int,int> pt; const int N=5e5+5; const int M=2e3+5; const int INF=0x7fffffff; const int mod=998244353; const double eps=1e-8; const double pi=acos(-1); LL n,m; struct in { int c,l,r; }f[N]; LL g[N]; LL gg[N]; LL sum[N<<2]; template<class T> inline void read(T &x) { char c; x=1; while((c=getchar())<'0'||c>'9') if(c=='-') x=-1; T res=c-'0'; while((c=getchar())>='0'&&c<='9') res=res*10+c-'0'; x*=res; } void update(int k,int l,int r,int pos,LL v) { if(l==r){ sum[k]=v; return ; } int mid=(l+r)>>1; if(mid>=pos) update(ls,pos,v); else update(rs,pos,v); sum[k]=sum[k<<1]+sum[k<<1|1]; } LL query(int k,int l,int r,int x,int y) { if(x<=l&&r<=y){ return sum[k]; } int mid=(l+r)>>1; LL res=0; if(mid>=x) res+=query(ls,x,y); if(mid<y) res+=query(rs,x,y); return res; } int main() { r(n); int ll=INF,rr=0; FOR(i,1,n){ rrr(f[i].c,f[i].l,f[i].r); g[f[i].c]++; ll=min(f[i].c,ll); rr=max(f[i].c,rr); } LL res; FOR(i,1,n){ if(f[i].l<=f[i].c&&f[i].c<=f[i].r){ res=1ll*(g[f[i].c]-1-gg[f[i].c])*gg[f[i].c]; update(1,ll,rr,f[i].c,res); } cout<<query(1,ll,rr,f[i].l,f[i].r)<<' '; gg[f[i].c]++; res=1ll*(g[f[i].c]-gg[f[i].c])*gg[f[i].c]; update(1,ll,rr,f[i].c,res); } return 0; }