828div3
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,p[N],n,T;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
for(int i=0;i<n;i++){
cin>>x;
p[x]=i;
}
int L=n,R=-1;
long long ans=0;
for(int i=0;i<n;i++){
L=min(L,p[i]),R=max(R,p[i]);
while(i+1<n&&L<=p[i+1]&&p[i+1]<=R)i++;
if(i==n-1){
ans++;break;}
int maxlen=(i+1)*2;
if(R-L+1>maxlen)continue;
int x=p[i+1];
if(x<L){
//x [L,R]
for(int j=x+1;j<=L;j++){
if(R-j+1>maxlen)continue;
ans+=min(n-1-R+1,maxlen-(R-j+1)+1);
}
}
if(x>R){
//[L,R] x
for(int j=R;j<x;j++){
if(j-L+1>maxlen)continue;
ans+=min(L-0+1,maxlen-(j-L+1)+1);
}
}
}
cout<<ans<<'\n';
}
}
659 div1
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,a[N],n,T;
string ans[]={
"DRAW\n","WIN\n","LOSE\n"};
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
vector<int>b(31,0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
for(int j=30;j>=0;j--)b[j]+=(x>>j&1);
}
int ok=0;
for(int j=30;j>=0;j--){
if(b[j]%2==0)continue;
if(b[j]%4==1||(n-b[j])&1){
ok=1;break;}
if(b[j]%4==3){
ok=2;break;}
}
cout<<ans[ok];
}
}
global round22 C
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,a[N],n,T;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
int b=0,a=0;
for(int i=1;i<=n;i++){
cin>>x;
if(x&1)b++;
else a++;
}
int ok=1;
if(b%4==1&&(a%2==0))ok=0;
if(b%4==2)ok=0;
if(ok)cout<<"Alice"<<'\n';
else cout<<"Bob"<<'\n';
}
}
828div3 E2
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=1e9;
int T,a,b,c,d;
map<int,int>mp;
typedef pair<int,int>PII;
typedef vector<PII> vi;
void solve(int a){
for(int i=2;i*i<=a;i++){
if(a%i==0){
while(a%i==0)a/=i,mp[i]++;
}
}
if(a>1)mp[a]++;
}
vi ans;
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a;
b/=2;
a=a*a;
}
return ans;
}
void dfs(int u,vi v,int i=1,int j=1){
if(u==v.size()){
int x=c/i*i;
int y=d/j*j;
if(x>a&&y>b)ans.push_back({
x,y});
return;
}
if(i>c||j>d)return;
if(ans.size())return;
int x=v[u].first;
int c=v[u].second;
for(int f=0;f<=c;f++){
dfs(u+1,v,i*qpow(x,f),j*qpow(x,c-f));
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>a>>b>>c>>d;
mp.clear();solve(a),solve(b);
vi v;
for(auto &[x,c]:mp)v.push_back({
x,c});
ans.clear();
dfs(0,v);
if(ans.size())cout<<ans[0].first<<" "<<ans[0].second<<'\n';
else cout<<"-1 -1\n";
}
}
edu137 E
#include<bits/stdc++.h>
using namespace std;
#define int long long
int p1,t1,p2,t2,h,s;
int f[5050],g[5050],dp[5050];
signed main(){
cin>>p1>>t1>>p2>>t2>>h>>s;
for(int i=0;i<=5000;i++)f[i]=1e18,g[i]=1e18,dp[i]=1e18;
f[0]=0;
for(int i=0;i<=h;i++){
for(int j=0;j<=h;j++){
int tf=max(t1* i ,t2* j );
int tg=max(t1*(i+1),t2*(j+1));
int x=i*(p1-s)+j*(p2-s);
int y=min(x,h);
f[y]=min(f[y],tf);
g[y]=min(g[y],tg);
}
}
f[0]=0;
for(int i=0;i<=h;i++){
for(int j=0;j<=h;j++){
int x=i+j+(p1+p2-s);
x=min(x,h);
f[x]=min(f[x],f[i]+g[j]);
}
}
cout<<f[h];
}
DDP
动态动态规划
也就是在动态规划处理静态问题的基础上加入修改操作
修改矩阵乘法变成 max矩阵加
比较典型的有带修子段和,带修树上最大权独立集(没有上司的舞会带修版)
传送门
#include<bits/stdc++.h>
#define end End
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N=4e5+10;
const int inf=0x7f7f7f7f;
struct Matrix{
int a[2][2];
Matrix(){
memset(a,-0x3f,sizeof a);}
Matrix operator*(Matrix b){
Matrix c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
{
c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);}
return c;
}
void pr(){
cout<<"a00="<<a[0][0]<<" a01="<<a[0][1]<<'\n';
cout<<"a10="<<a[1][0]<<" a11="<<a[1][1]<<'\n';
cout<<'\n';
}
}V[N];
int n,m,h[N],e[N],ne[N],idx,sz[N],fa[N],dep[N];
int a[N],top[N],id[N],dfn[N],end[N];
int son[N];
struct SegTree{
int L[N],R[N];
Matrix M[N];
void pushup(int u){
M[u]=M[ls]*M[rs];}
void build(int u,int l,int r){
L[u]=l,R[u]=r;
if(l==r){
M[u]=V[dfn[l]];
// cout<<"u="<<u<<" L="<<l<<" R="<<r<<'\n';
// M[u].pr();
return;
}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(u);
}
void modify(int u,int x){
if(L[u]==R[u]){
M[u]=V[dfn[x]];
return;
}
int mid=L[u]+R[u]>>1;
if(x<=mid)modify(ls,x);
else modify(rs,x);
pushup(u);
}
// 查询一个点的 DP 值,相当于查询这条重链上链尾矩阵和链中转移矩阵的 '*' 积
Matrix query(int u,int l=1,int r=n){
if(L[u]==l&&R[u]==r)return M[u];
int mid=L[u]+R[u]>>1;
if(r<=mid)return query(ls,l,r);
else if(l>mid)return query(rs,l,r);
else return query(ls,l,mid)*query(rs,mid+1,r);
}
}T;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int F=0){
sz[u]=1,fa[u]=F,dep[u]=dep[F]+1;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==F)continue;
dfs1(j,u);
sz[u]+=sz[j];
if(sz[son[u]]<sz[j])son[u]=j;
}
}
int cntv;
int f[N][2],g[N][2];
void dfs2(int u,int t=1){
cntv++;
id[u]=cntv,dfn[cntv]=u;
top[u]=t;
end[t]=max(end[t],cntv);
// 第二次树剖时直接更新 F, G 数组(这里直接将 G 放入矩阵更新)
f[u][0]=0,f[u][1]=a[u];
V[u].a[0][0]=0, V[u].a[0][1]=0;
V[u].a[1][0]=a[u];//,V[u].a[1][1]=inf;
if(son[u]){
dfs2(son[u],t);
f[u][0]+=max(f[son[u]][0],f[son[u]][1]);
f[u][1]+=f[son[u]][0];
}
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==fa[u]||j==son[u])continue;
dfs2(j,j);
f[u][0]+=max(f[j][0],f[j][1]);
f[u][1]+=f[j][0];
V[u].a[0][0]+=max(f[j][0],f[j][1]);
V[u].a[0][1]=V[u].a[0][0];
V[u].a[1][0]+=f[j][0];
}
}
void update_path(int u,int w){
V[u].a[1][0]+=w-a[u];
a[u]=w;
Matrix pre,nxt;
while(u!=0){
// 计算贡献时,应当用一个 bef 矩阵还原出少掉这个轻儿子的情况,再将 aft 加入更新
pre=T.query(1,id[top[u]],end[top[u]]);
T.modify(1,id[u]);
nxt=T.query(1,id[top[u]],end[top[u]]);
u=fa[top[u]];
V[u].a[0][0]+=max(nxt.a[0][0],nxt.a[1][0])-max(pre.a[0][0],pre.a[1][0]);
V[u].a[0][1]=V[u].a[0][0];
V[u].a[1][0]+=nxt.a[0][0]-pre.a[0][0];
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
memset(h, -1, sizeof h);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
dfs1(1);dfs2(1);
T.build(1,1,n);
// cout<<"f="<<max(f[1][0],f[1][1])<<'\n';
// Matrix ans=T.query(1,id[1],end[1]);
// cout<<"V="<<max(ans.a[0][0],ans.a[1][0])<<'\n';
while(m--){
int u,w;
cin>>u>>w;
update_path(u,w);
Matrix ans=T.query(1,id[1],end[1]);
cout<<max(ans.a[0][0],ans.a[1][0])<<'\n';
}
}
arc151 C
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
#define int long long
const int N=2e5+10;
int n,m,ans;
typedef pair<int,int>PII;
PII a[N];
string op[]={
"Aoki","Takahashi"};
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y;
sort(a+1,a+1+m);
if(!m){
if(n&1)ans=1;
cout<<op[ans];
return 0;
}
ans^=a[1].x-1;
ans^=n-a[m].x;
for(int i=2;i<=m;i++){
if(a[i].y==a[i-1].y)ans^=1;
}
if(ans)ans=1;
cout<<op[ans];
}
edu137F
考虑每一个数字的贡献,也就是考虑让数字保留在最终集合里面
发现对于数字x的贡献,只有最后一次出现x的集合Si,前面无论操作是啥都不用管,后面保留下来就行了
这样的就是3的i-2次方乘2的n-i+1次方,但是起点需要特判
解法一就是线段树维护每个数字最后一次出现的下标(最大下标)
解法二就是ddp,线段树维护每一个数字,然后你需要对整棵树做dp,维护矩阵链乘注意细节
#include<bits/stdc++.h>
#define ls u<<1
#define rs u<<1|1
using namespace std;
#define int long long
const int mod=998244353;
const int N=3e5+10;
int n,a[N*4],l,r,ans;
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
b/=2;
a=a*a%mod;
}
return ans;
}
void pushdown(int u){
a[ls]=max(a[ls],a[u]);
a[rs]=max(a[rs],a[u]);
}
void update(int u,int ql,int qr,int i,int l=0,int r=3e5){
if(ql<=l&&r<=qr)return a[u]=i,void();
if(ql>r||qr<l)return;
int mid=l+r>>1;
pushdown(u);
update(ls,ql,qr,i,l,mid);
update(rs,ql,qr,i,mid+1,r);
}
int query(int u,int x,int l=0,int r=3e5){
if(l==r)return a[u];
int mid=l+r>>1;
pushdown(u);
if(x<=mid)return query(ls,x,l,mid);
return query(rs,x,mid+1,r);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
memset(a,-1,sizeof a);
cin>>n;
for(int i=1;i<=n;i++){
cin>>l>>r;
update(1,l,r,i);
}
for(int i=0;i<=3e5;i++){
int j=query(1,i);
if(j==-1)continue;
if(j==1)ans+=qpow(2,n-1);
else ans+=qpow(3,j-2)*qpow(2,n-j+1)%mod;
ans%=mod;
}
cout<<ans;
}
#include<bits/stdc++.h>
#define int long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int mod=998244353;
const int N=3e5+1;
int m,l,r,x,ans;
struct Matrix{
// int a[2][2]={1,0,0,1};//不可以这样初始化
int a[2][2];
Matrix(){
memset(a,0,sizeof a);
a[0][0]=1;
a[1][1]=1;
}
Matrix(int i1,int i2,int i3,int i4){
a[0][0]=i1;
a[0][1]=i2;
a[1][0]=i3;
a[1][1]=i4;
}
Matrix operator*(Matrix b){
Matrix c;
memset(c.a,0,sizeof c.a);
//记住教训,一定要清空第三方数组
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
c.a[i][j]+=a[i][k]*b.a[k][j];
c.a[i][j]%=mod;
}
}
}
return c;
}
bool operator==(Matrix B){
int ok=1;
for(int i=0;i<2;i++)for(int j=0;j<2;j++)
if(a[i][j]!=B.a[i][j])return 0;
return 1;
}
void pr(){
for(int i=0;i<2;i++){
for(int j=0;j<2;j++)cout<<" a["<<i<<"]["<<j<<"]="<<a[i][j];
cout<<'\n';
}
}
}E;
struct Segmentree{
Matrix a[N*4];
void pushdown(int u){
if(a[u]==E)return;
a[ls]=a[ls]*a[u];
a[rs]=a[rs]*a[u];
a[u]=E;
//变回单位矩阵
}
void update(int u,int ql,int qr,Matrix x,int l=0,int r=3e5){
if(ql<=l&&r<=qr){
return a[u]=a[u]*x,void();
}
if(ql>r||qr<l)return;
pushdown(u);
int mid=l+r>>1;
update(ls,ql,qr,x,l,mid);
update(rs,ql,qr,x,mid+1,r);
}
Matrix query(int u,int x,int l=0,int r=3e5){
if(l==r)return a[u];
pushdown(u);
int mid=l+r>>1;
if(x<=mid)return query(ls,x,l,mid);
return query(rs,x,mid+1,r);
}
}T;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
// E.pr();
// E=E*Matrix({1,0,0,0});
// E.pr();
cin>>m;
cin>>l>>r;
T.update(1,0,l-1,{
1,0,0,0});
T.update(1,l,r,{
0,1,0,0});
T.update(1,r+1,3e5,{
1,0,0,0});
for(int i=1;i<m;i++){
cin>>l>>r;
T.update(1,0,l-1,{
3,0,1,2});
T.update(1,l,r,{
1,2,1,2});
T.update(1,r+1,3e5,{
3,0,1,2});
}
for(int x=0;x<=3e5;x++){
ans+=T.query(1,x).a[0][1];
ans%=mod;
}
cout<<ans;
}
2022寒假基础训练营补题
6
B
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],n,T,ans,p[N];
const int mod=998244353;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
p[0]=1;
for(int i=1;i<N;i++)p[i]=p[i-1]*2%mod;
while(T--){
ans=1;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
int j=i;
while(j<n&&a[j]==a[j+1])j++;
int len=j-i+1;
int ni=a[i-1]<a[i]&&a[i]<a[j+1];
int sh=a[i-1]>a[i]&&a[i]>a[j+1];
if(i>1&&j<n&&(ni||sh))ans=ans*p[len]%mod;
else ans=ans*(p[len]-1)%mod;
i=j;
}
cout<<ans<<'\n';
}
}
C
离线,找特性,猜结论
把合法答案的放进栈里面,二分找不得不选的美丽数组
我是l-1,往右边找第一个sumj满足sumj - sumi-1 < 0
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e6+10;
int T,n,a[N],L[N],R[N],x,ans[N],stk[N],top,m;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];
for(int i=1;i<=m;i++)cin>>L[i]>>R[i];
top=0;
stk[++top]=n;
int j=n-1;
for(int i=m;i>=1;i--){
while(j>=L[i]-1){
while(top&&a[stk[top]]>=a[j])top--;
stk[++top]=j;
j--;
}
int l=1,r=top;
while(l<r){
int mid=l+r>>1;
if(stk[mid]<R[i])r=mid;
else l=mid+1;
}
ans[i]=top-l+1;
}
for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';
}
}
G
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N=1010;
char a[N][N];
int n,m,T,f[N][N];
int xx[]={
-1,1,0,0};
int yy[]={
0,0,-1,1};
char dir[]={
'U','D','L','R'};
typedef pair<int,int>PII;
int pre[N][N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)cin>>a[i][j],f[i][j]=1e9;
}
deque<PII>q;
q.push_back({
1,1});
f[1][1]=0;
while(q.size()){
int x=q.front().x;
int y=q.front().y;
q.pop_front();
for(int i=0;i<4;i++){
int dx=x+xx[i];
int dy=y+yy[i];
if(dx<1||dx>n||dy<1||dy>m)continue;
if(f[x][y]+(a[x][y]!=dir[i])<f[dx][dy]){
f[dx][dy]=f[x][y]+(a[x][y]!=dir[i]);
// pre[dx][dy]={x,y};
pre[dx][dy]=i;
if(a[x][y]==dir[i])q.push_front({
dx,dy});
else q.push_back({
dx,dy});
}
}
}
cout<<f[n][m]<<"\n";
while(1){
if(n==1&&m==1)break;
int i=pre[n][m];
int x=n-xx[i];
int y=m-yy[i];
if(a[x][y]!=dir[i])cout<<x<<" "<<y<<" "<<dir[i]<<"\n";
n=x,m=y;
}
}
}
H
非常非常好的一道题
#include<bits/stdc++.h>
using namespace std;
int T,n,ans,x;
string op[]={
"No\n","Yes\n"};
unordered_map<int,int>mp;
//必败态只能走到必胜态,走不到必败态
int dfs(int u){
if(mp.count(u))return mp[u];
int bai=0;
if(u&1)bai|=!dfs(u-1);
for(int i=1;i<10;i++){
if(u>>i&1){
for(int j=0;j<i;j++){
int x=u^(1<<i)^(1<<j);
bai|=!dfs(x);
}
}
}
if(!bai)return mp[u]=0;
else return mp[u]=1;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
mp[0]=0;
for(int i=(1<<10)-1;i;i--){
if(!mp.count(i))dfs(i);
}
cin>>T;
while(T--){
cin>>n;
x=0;
for(int i=0;i<n;i++){
char c;
cin>>c;
if(c=='w')x+=1<<i;
}
cout<<op[mp[x]];
}
}
J
51nod1514 美妙的序列 分治NTT
牛客寒假基础训练营第一场
D
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+10;
int T,n;
int a[]={
2,3,5,7,11,13,17,19,23,29,31};
int check(int x){
for(int i=2;i*i<=x;i++){
if(x%i==0)return 0;
}
return 1;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n;
if(n==1){
cout<<-1<<'\n';
continue;
}
int mi=1;
for(int i=0;i<10;i++){
if(mi*a[i]>n)break;
mi*=a[i];
}
while(!check(n))n--;
cout<<mi<<" "<<n<<'\n';
}
}
F
解法一,找性质,考虑每个数字对答案的贡献求前缀
按照题意,偶数时取min(中间左,中间右),
要想变成中位数,那么比m大的数字个数>=比m小的个数+1
牛客题解传送门
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int T,n,m,a[N],x;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;
int ans=0;
for(int i=1;i<=n;i++){
cin>>x;
if(x>=m)ans++;
else ans--;
}
if(ans<=0)ans=-1;
cout<<ans<<'\n';
}
}
解法2,线段树优化dp(垃圾)
这道题可以拓展,也就是说它的m给你了,那么所有的ai就都可以映射到1,-1
我可以改为给q询问L,R之间可划分为中位数的最大段数
B
解法1,分块
#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=2e5+10,D=500;
int n,q,a[N],f[N];
string s;
// unordered_map<int,int>mp[3];
int mp[3][N];
int vis[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>q>>s;
s=' '+s;
int l=1;
int v[]={
0,1,2};
for(int i=1;i<=n;i++){
if(s[i]=='W')for(int j=0;j<3;j++)v[j]++;
if(s[i]=='L')for(int j=0;j<3;j++)if(v[j]%3)v[j]--;
if(i-l+1==D){
vis[l]=1;
for(int j=0;j<3;j++)mp[j][l]=v[j]-j;
l+=D;
for(int j=0;j<3;j++)v[j]=j;
}
}
while(q--){
int l,r,t;
cin>>l>>r>>t;
while(l<=r){
if(vis[l]&&l+D-1<=r){
t+=mp[t%3][l],l+=D;
}
else {
if(s[l]=='W')t++;
if(s[l]=='L')if(t%3)t--;
l++;
}
}
cout<<t<<'\n';
}
}
解法2,倍增解决,
如何处理好区间合并
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int f[N][21][3],n,q,l,r,v;
string s;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>q>>s;
s=' '+s;
for(int i=1;i<=n;i++){
for(int j=0;j<3;j++){
if(j==0&&s[i]=='L')f[i][0][j]=0;
else if(s[i]=='L')f[i][0][j]=-1;
else if(s[i]=='W')f[i][0][j]=1;
}
}
for(int k=1;k<=18;k++){
for(int i=1;i<=n;i++){
for(int j=0;j<3;j++){
int x=(j+f[i][k-1][j])%3;
f[i][k][j]=f[i][k-1][j]+f[i+(1<<k-1)][k-1][x];
}
}
}
while(q--){
cin>>l>>r>>v;
for(int k=18;k>=0;k--){
if((1<<k)<=r-l+1){
v+=f[l][k][v%3];
l+=1<<k;
}
}
cout<<v<<'\n';
}
}
K
dp,枚举初始状态,初始状态确定了才可以进行枚举
这道题难点就是初始状态不确定无法进行枚举
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,f[N][3][3],ans;//f[i][j][k]表示第i位是j前面是k是否合法RGB==012
int dp[N];
string s;
int check(int op,int a,int b,int c){
int cnt[3]={
0,0,0};
cnt[a]++,cnt[b]++,cnt[c]++;
if(op==0)return cnt[0]>cnt[1];
if(op==1)return cnt[0]<cnt[1];
if(op==2)return cnt[0]==cnt[1];
return 1;
}
int cal(int i1,int i2){
memset(f,-1,sizeof f);
f[2][i2][i1]=0;
if(i2==1)f[2][i2][i1]++;
if(i1==1)f[2][i2][i1]++;
for(int i=3;i<=n;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
if(f[i-1][j][k]==-1)continue;
if(s[i]=='R')for(int x=0;x<3;x++)if(check(0,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
if(s[i]=='G')for(int x=0;x<3;x++)if(check(1,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
if(s[i]=='B')for(int x=0;x<3;x++)if(check(2,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
}
}
}
int ma=-1;
for(int i=0;i<3;i++)for(int j=0;j<3;j++)ma=max(ma,f[n][i][j]);
return ma;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>s;
s=' '+s;
ans=-1;
for(int i=0;i<3;i++)for(int j=0;j<3;j++)ans=max(ans,cal(i,j));
cout<<ans;
}
H
值域树状数组,考虑每一个数字的贡献
/*
ai与多少个aj加起来是大于1000的,与多少个aj加起来是小于1000的
总和就是 x (ai+aj-1000) + y (1000-ai-aj)
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,a[N],ans,s,t;
struct Tree{
int tr[1010];
void add(int x,int c){
x++;
for(int i=x;i<=1001;i+=i&-i)tr[i]+=c;
}
int sum(int x){
x++;
int ans=0;
for(int i=x;i;i-=i&-i)ans+=tr[i];
return ans;
}
}cnt,val;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
s+=a[i];
cnt.add(a[i],1);
val.add(a[i],a[i]);
t+=abs(a[i]+a[i]-1000);
}
for(int i=1;i<=n;i++){
int y=cnt.sum(1000-a[i]);
int x=n-y;
int v=val.sum(1000-a[i]);
int Y=y*1000-y*a[i]-v;
int X=x*a[i]+(s-v)-x*1000;
ans+=X+Y;
}
cout<<(ans+t)/2;
}
I
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int T,n,m;
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
b/=2;
a=a*a%mod;
}
return ans;
}
int inv(int a){
return qpow(a,mod-2);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;
int p=2*inv(qpow(2,n));
p=1-p;
cout<<(m*p%mod+mod)%mod<<'\n';
}
}
第二场
G
你记录的信息只能是根到我这个节点的,而不可能是我到根节点的,因为这是多对一和一对一的关系
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,m,a[N];
signed fa[N][21];
int dep[N],up[N],d[N];
vector<int>g[N];
//sum[u]表示从u出发跳到根节点的代价
//那么从根节点跳到u的代价就是-sum
void dfs(int u,int F=0){
if(a[u]>a[F])up[u]=up[F]+0;
else up[u]=up[F]+a[F]-a[u];
if(a[F]>a[u])d[u]=d[F]+0;
else d[u]=d[F]+a[u]-a[F];
dep[u]=dep[F]+1;
fa[u][0]=F;
for(int k=1;k<=20;k++)fa[u][k]=fa[fa[u][k-1]][k-1];
for(auto j:g[u]){
if(j==F)continue;
dfs(j,u);
// if(a[u]>a[j])d[u]=d[j]+0;
// else d[u]=d[j]+a[j]-a[u];
}
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
for(int k=20;k>=0;k--)if(dep[fa[a][k]]>=dep[b])a=fa[a][k];
if(a==b)return a;
for(int k=20;k>=0;k--){
if(fa[a][k]!=fa[b][k]){
a=fa[a][k],b=fa[b][k];
}
}
return fa[a][0];
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1);
// for(int i=1;i<=n;i++)cout<<"up["<<i<<"]="<<up[i]<<'\n';
// for(int i=1;i<=n;i++)cout<<"down["<<i<<"]="<<d[i]<<'\n';
while(m--){
int u,v;
cin>>u>>v;
int f=lca(u,v);
// cout<<"u="<<u<<" v="<<v<<" f="<<f<<'\n';
cout<<a[u]+up[u]-up[f]+d[v]-d[f]<<'\n';
}
}