CSP模拟<反思> (3~15)
csp模拟3#
回文#
区间
暴力的话 可以拿到
让两个点从两头同时进行转移,发现可以计算出并省掉一维
设
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int mod=993244853;
char s[502];
int a[505][505];
int f[502][502][502];
signed main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
a[i][j]=s[j]-'a';
}
}
if(a[1][1]==a[n][m]){
f[1][1][n]=1;
}
int r=(n+m-1)/2;
for(int i=1;i<=n;i++){
for(int j=1;j+i<=r+1;j++){
for(int x=n;x>=i;x--){
if(f[i][j][x]==0) continue;
int y=m-i-j-x+2+n;
if(a[i+1][j]==a[x][y-1]) f[i+1][j][x]=(f[i+1][j][x]+f[i][j][x])%mod;//上 左
if(a[i+1][j]==a[x-1][y]) f[i+1][j][x-1]=(f[i+1][j][x-1]+f[i][j][x])%mod;//上 下
if(a[i][j+1]==a[x][y-1]) f[i][j+1][x]=(f[i][j+1][x]+f[i][j][x])%mod;//右 左
if(a[i][j+1]==a[x-1][y]) f[i][j+1][x-1]=(f[i][j+1][x-1]+f[i][j][x])%mod;//右 下
}
}
}
int ans=0;
if((n+m-1)%2==0){
for(int i=1;i<=n;i++){
ans+=f[i][r-i+1][i];ans%=mod;
ans+=f[i][r-i+1][i+1];ans%=mod;
}
cout<<ans<<endl;
return 0;
}
else{
for(int i=1;i<=n;i++){
ans+=f[i][(m+n)/2-i+1][i];ans%=mod;
}
cout<<ans<<endl;
return 0;
}
}
/*
3 4
noip
ffff
pion
10 12
abbcbdbababa
bcccdcdccccb
bcccccccccca
ccccdcdcdcdb
bdcdcccccccd
dcccccccdcdb
bdcdcdcdcccc
accccccccccb
bccccdcdcccb
abababdbcbba
4 5
wwwww
wwwww
wwwww
wwwwa
3 3
abc
bcb
cba
*/
快速排序#
考试的时候没看懂让干啥。
观察它发现,排完序后每个
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
char s[15];
struct asd{
int id,data;
}b[N];
map<int,int>flat;
int n;
bool amp(asd a,asd b){
if(a.data==b.data){
return a.id<b.id;
}
return a.data<b.data;
}
int main(){
int T;
scanf("%d",&T);
for(int p=1;p<=T;p++){
scanf("%d",&n);
flat.clear();
memset(b,0,sizeof(b));
int ma=0,w=0;
int ans=0;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len=strlen(s+1);
int a=0;
if(s[1]=='n'){
flat[w]++;
}
else{
for(int j=1;j<=len;j++){
a=a*10+s[j]-'0';
}
// cout<<a<<endl;
ans++;
b[ans].data=a;
b[ans].id=ans;
if(ma<=a){
ma=a;
w=ans;
}
}
}
sort(b+1,b+ans+1,amp);
for(int i=0;i<=ans;i++){
if(i!=0) cout<<b[i].data<<" ";
for(int j=1;j<=flat[b[i].id];j++){
cout<<"nan ";
}
}
cout<<endl;
}
}
混乱邪恶#
不要随便用 map
这里学习了一下
点击查看代码
struct asd{
int id,data,id1,id2;
friend bool operator <(asd a,asd b){//注意,multiset是具有顺序的,所以你结构体要进行自我排序,否则会报错。
return a.data<b.data;
}
}b[N];
multiset < asd > s;//定义一个multiset ,可以为结构体,int,pair等等,Multiset和Set的区别就是可以保存多个相同的对象
multiset< asd >::iterator t1,t2;// 定义迭代器
t1=s.begin();//返回第一个元素的位置
t2=s.end();//返回最后一个元素的后一个位置 注意这是后一个
asd qwq=*t1;//得到第一个位置元素
//s.erase(v):删除值为v的所有元素。
//s.erase(it):删除迭代器it处的元素。
//s.find(v):返回一个等于v的迭代器指针。如果不存在值等于v的元素,则返回s.end()
//s.lower_bound(v):返回第一个大于等于v的迭代器指针。
//s.upper_bound(v):返回第一个大于v的迭代器指针。
//s.count(v):返回值等于v的元素个数,数据类型为unsigned longlong int,如果不存在返回0,时间复杂度未知,如果重复的个数过多可能会慢。
//可以用s.erase(s.find(v))来删除值为v的一个元素
校门外歪脖树上的鸽子#
首先考虑暴力,类似线段树,首先你要先dfs出每个节点子树的左右节点,然后修改查询时要考虑左儿子右边界是否大于查询左边界,右儿子左边界是否小于查询有边界,进行
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2*1e5+5;
int tr[N*4][3];
struct asd{
int l,r,data;
}tree[N*4];
int n,m;
void dfs(int x){
if(x<=n){
tree[x].l=tree[x].r=x;
return;
}
dfs(tr[x][0]),dfs(tr[x][1]);
if(tree[tr[x][0]].l>=tree[tr[x][1]].l){
swap(tr[x][1],tr[x][0]);
}
tree[x].l=tree[tr[x][0]].l;
tree[x].r=tree[tr[x][1]].r;
}
void change(int p,int l,int r,int d){
if(tree[p].l>=l && tree[p].r<=r){
tree[p].data+=(tree[p].r-tree[p].l+1)*d;
return;
}
if(tree[tr[p][0]].r>=l) change(tr[p][0],l,r,d);
if(tree[tr[p][1]].l<=r) change(tr[p][1],l,r,d);
}
int ask(int p,int l,int r){
if(tree[p].l>=l && tree[p].r<=r){
return tree[p].data;
}
int ans=0;
if(tree[tr[p][0]].r>=l) ans+=ask(tr[p][0],l,r);
if(tree[tr[p][1]].l<=r) ans+=ask(tr[p][1],l,r);
return ans;
}
bool flat[N*2];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%lld%lld",&x,&y);
tr[n+i][0]=x,tr[n+i][1]=y;
flat[x]=flat[y]=1;
}
int root;
for(int i=1;i<=n*2-1;i++){
if(flat[i]==0){
root=i;
break;
}
}
dfs(root);
for(int i=1;i<=m;i++){
int op;
scanf("%lld",&op);
if(op==1){
int l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
change(root,l,r,d);
}
else{
int l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",ask(root,l,r));
}
}
}
定义 isa 表示 a 是否是它父亲的左儿子
定义 ffa 表示 a的真祖先中第一个和 a is 值不同的祖先的兄弟节点
连接 a,ffa ,显然仍能得到一颗以原来根为根的树(以后就说现树)。
如何建:
查询两个点
首先由左节点出发向右上走到头为
开个栈,每次先将当前点的左儿子与栈顶元素相连,然后将当前点左儿子压入栈,遍历当前点右子树,再将左儿子弹出栈,再遍历左子树,如此得到。可以在
点击查看代码
void Do(int th,int x){
if(!ch[th][0]) return;
add(x,ch[th][0]);
Do(ch[th][1],ch[th][0]);
Do(ch[th][0],x);
}
void Do1(int th,int x){
if(!ch[th][0]) return;
add(x,ch[th][1]);
Do1(ch[th][0],ch[th][1]);
Do1(ch[th][1],x);
}
Do(root,root);
Do1(root,root);
先对于节点
那么从
考虑三种情况:
1:
2:
3:
因此可以用树剖+线段树维护。
线段树维护节点状态之和,可以打延迟标记。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4*1e5+5;
int n,m,root;
int ch[N*2][3];
struct asd{
int l,r,data;
}t[N*2];
struct qwe{
int l,r,data,num,lazy;
}tr[1600010];
int ll[N*2],rr[N*2];
int head[N*2],ver[N*2],nex[N*2],tot=0;
int fa[N*2],size[N*2],son[N*2],top[N*2],d[N*2];
int _fa[N*2],_size[N*2],_son[N*2],_top[N*2],_d[N*2],_id[N*2],_rk[N*2],cnt=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
void dfs(int x){
if(x<=n){
t[x].l=t[x].r=x;
return;
}
dfs(ch[x][0]);
dfs(ch[x][1]);
if(t[ch[x][0]].l>=t[ch[x][1]].l){
swap(ch[x][1],ch[x][0]);
}
t[x].l=t[ch[x][0]].l;
t[x].r=t[ch[x][1]].r;
}
void dfs1(int x){
if(x<=n) return;
rr[ch[x][0]]=rr[x],ll[ch[x][0]]=ch[x][0];
dfs1(ch[x][0]);
ll[ch[x][1]]=ll[x],rr[ch[x][1]]=ch[x][1];
dfs1(ch[x][1]);
}
void dfs_y1(int x,int f){
if(!x) return;
d[x]=d[f]+1;
fa[x]=f;
size[x]=1;
dfs_y1(ch[x][0],x); size[x]+=size[ch[x][0]];
dfs_y1(ch[x][1],x); size[x]+=size[ch[x][1]];
if(size[ch[x][0]]<size[ch[x][1]]) son[x]=ch[x][1];
else son[x]=ch[x][0];
}
void dfs_y2(int x,int tp){
if(!x) return;
top[x]=tp;
if(son[x]) dfs_y2(son[x],tp);
if(ch[x][0]!=son[x]) dfs_y2(ch[x][0],ch[x][0]);
else dfs_y2(ch[x][1],ch[x][1]);
}
int ask_lca(int x,int y){//原树lca
int fx=top[x],fy=top[y];
while(fx!=fy){
if(d[fx]>d[fy]) x=fa[fx],fx=top[x];
else y=fa[fy],fy=top[y];
}
if(d[x]<d[y]) return x;
else return y;
}
void dfs_x1(int x,int f){
_d[x]=_d[_fa[x]]+1;
_size[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
_fa[y]=x;
dfs_x1(y,x);
_size[x]+=_size[y];
if(_size[_son[x]]<_size[y]){
_son[x]=y;
}
}
}
void dfs_x2(int x,int tp){
_id[x]=++cnt;
_rk[cnt]=x;
_top[x]=tp;
if(_son[x]) dfs_x2(_son[x],tp);
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==_fa[x]) continue;
if(y!=_son[x]){
dfs_x2(y,y);
}
}
}
void Do(int th,int x){
if(!ch[th][0]) return;
add(x,ch[th][0]);
Do(ch[th][1],ch[th][0]);
Do(ch[th][0],x);
}
void Do1(int th,int x){
if(!ch[th][0]) return;
add(x,ch[th][1]);
Do1(ch[th][0],ch[th][1]);
Do1(ch[th][1],x);
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r){
int id=_rk[l];
tr[p].num=(t[id].r-t[id].l+1);
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p].num=tr[p*2].num+tr[p*2+1].num;
}
void pushdown(int p){
if(tr[p].lazy){
tr[p*2].data+=tr[p*2].num*tr[p].lazy;
tr[p*2].lazy+=tr[p].lazy;
tr[p*2+1].data+=tr[p*2+1].num*tr[p].lazy;
tr[p*2+1].lazy+=tr[p].lazy;
tr[p].lazy=0;
}
}
void change(int p,int l,int r,int w){
if(tr[p].l>=l && tr[p].r<=r){
tr[p].data+=tr[p].num*w;
tr[p].lazy+=w;
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change(p*2,l,r,w);
if(r>mid) change(p*2+1,l,r,w);
tr[p].data=tr[p*2].data+tr[p*2+1].data;
return;
}
int ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r){
return tr[p].data;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
int ans=0;
if(l<=mid) ans+=ask(p*2,l,r);
if(r>mid) ans+=ask(p*2+1,l,r);
return ans;
}
void chan(int l,int r,int w){
int lca=ask_lca(l,r),ans=0;
l=rr[l],r=ll[r];
if(d[l]<=d[lca] && d[r]<=d[lca]){
change(1,_id[lca],_id[lca],w);
return;
}
if(d[l]<=d[lca]){
l=ch[lca][0];
change(1,_id[l],_id[l],w);
}
else{
int fx=_top[l];
while(_d[fx]>_d[ch[lca][1]]){
change(1,_id[fx],_id[l],w);
l=_fa[fx],fx=_top[l];
}
change(1,_id[ch[lca][1]]+1,_id[l],w);
}
if(d[r]<=d[lca]){
r=ch[lca][1];
change(1,_id[r],_id[r],w);
}
else{
int fx=_top[r];
while(_d[fx]>_d[ch[lca][0]]){
change(1,_id[fx],_id[r],w);
r=_fa[fx],fx=_top[r];
}
change(1,_id[ch[lca][0]]+1,_id[r],w);
}
}
int askk(int l,int r){
int lca=ask_lca(l,r),ans=0;
l=rr[l],r=ll[r];
if(d[l]<=d[lca] && d[r]<=d[lca]){
ans+=ask(1,_id[lca],_id[lca]);
return ans;
}
if(d[l]<=d[lca]){
l=ch[lca][0];
ans+=ask(1,_id[l],_id[l]);
}
else{
int fx=_top[l];
while(_d[fx]>_d[ch[lca][1]]){
ans+=ask(1,_id[fx],_id[l]);
l=_fa[fx],fx=_top[l];
}
ans+=ask(1,_id[ch[lca][1]]+1,_id[l]);
}
if(d[r]<=d[lca]){
r=ch[lca][1];
ans+=ask(1,_id[r],_id[r]);
}
else{
int fx=_top[r];
while(_d[fx]>_d[ch[lca][0]]){
ans+=ask(1,_id[fx],_id[r]);
r=_fa[fx],fx=_top[r];
}
ans+=ask(1,_id[ch[lca][0]]+1,_id[r]);
}
return ans;
}
bool flat[N*2];
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%lld%lld",&x,&y);
ch[n+i][0]=x,ch[n+i][1]=y;
flat[x]=flat[y]=1;
}
for(int i=1;i<=n*2-1;i++){
if(flat[i]==0){
root=i;
break;
}
}
dfs(root);
ll[root]=root,rr[root]=root;
dfs1(root);
Do(root,root);
Do1(root,root);
dfs_y1(root,0);
dfs_y2(root,root);
dfs_x1(root,0);
dfs_x2(root,root);
build(1,1,cnt);
for(int i=1;i<=m;i++){
int op;
scanf("%lld",&op);
if(op==1){
int l,r,d;
scanf("%lld%lld%lld",&l,&r,&d);
chan(l,r,d);
}
else{
int l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",askk(l,r));
}
}
}
csp模拟4#
最长上升子序列#
题目大意为给出一个长度为 kk 的最长上升序列,求 11 到 nn 合法排列中字典序最小的一个。
思考当给出的
不妨令
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+10;
int a[N];
int b[N];
bool ask[N];
int tot=1;
int main(){
int n,k;
scanf("%d%d",&n,&k);
if(k==1){
for(int i=n;i>=1;i--){
cout<<i<<" ";
}
return 0;
}
for(int i=1;i<=k;i++){
scanf("%d",&a[i]);
ask[a[i]]=1;
}
tot=1;
while(tot<=n && ask[tot]){
tot++;
}
for(int i=1;i<=k;i++){
if(i==k){
for(int j=n;j>a[i];j--){
ask[j]=1;
printf("%d ",j);
}
}
printf("%d ",a[i]);
if(tot<a[i] && i!=k){
ask[tot]=1;
cout<<tot<<" ";
tot++;
while(tot<=n && ask[tot]){
tot++;
}
}
}
for(int i=n;i>=1;i--){
if(ask[i]==0){
cout<<i<<" ";
}
}
}
独特序列#
定义 f[i] 表示以 i 结尾的独特序列。
pre[i] 表示上一次出现 数a[i] 的位置。
考虑转移:
在考虑优化,用树状数组,每次算完
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int N=2*1e5+10;
int a[N];
int c[N];
int f[N];
int pre[N];
int flat[N];
int n;
int lowbit(int x){
return x&(-x);
}
void add(int x,int d){
if(x==0) return;
for(;x<=N;x+=lowbit(x)){
c[x]=(c[x]+d+mod)%mod;
}
}
int ask(int x){
if(x==0) return 0;
int ans=0;
for(;x;x-=lowbit(x)){
ans=(ans+c[x])%mod;
}
return ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
pre[i]=flat[a[i]];
flat[a[i]]=i;
}
for(int i=1;i<=n;i++){
if(pre[i]==0){
f[i]=(ask(i-1)+1)%mod;
}
else{
f[i]=(ask(i-1)-ask(pre[i]-1)+mod)%mod;
add(pre[i],-f[pre[i]]);
}
add(i,f[i]);
}
cout<<ask(n)<<endl;
}
最大GCD#
假二分可得65。
在卡一下时间,特判特解,就可A掉。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3*1e5+10;
int mi=(1ll<<32);
int a[N];
int n,k;
int check(int t){
int ans=0;
for(int i=1;i<=n;i++){
if(a[i]%t==0) continue;
if(a[i]<t){
ans+=(t-a[i]);
}
else{
ans+=(t-a[i]%t);
}
}
if(ans<=k) return 1;
else return 0;
}
signed main(){
double st=clock();
scanf("%lld%lld",&n,&k);
int ll;
int sum=0;
int ma=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
ma=max(a[i],ma);
mi=min(a[i],mi);
if(i==1) ll=a[i];
else ll=__gcd(ll,a[i]);
}
if(sum+k>=ma*n){
cout<<ma+((sum+k)-ma*n)/n<<endl;
return 0;
}
int l=1,r=mi+k;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)) l=mid;
else{
r=mid-1;
}
}
int w=l;
double ed;
for(int i=l+1;i<=mi+k;i++){
if(check(i)){
w=i;
}
ed=clock();
if((ed-st)/CLOCKS_PER_SEC>=0.790) {
cout<<w;
return 0;
}
}
}
正解:
if(sum+k>=ma*n){ cout<<ma+((sum+k)-ma*n)/n<<endl; return 0; }
思考普遍情况,最大边界为
如何判断: 将序列补成
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3*1e5+10;
int mi=(1ll<<32);
int a[N];
int n,k;
int num[N],num1[N];
signed main(){
double st=clock();
scanf("%lld%lld",&n,&k);
int ll;
int sum=0;
int ma=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
num[a[i]]++;
sum+=a[i];
ma=max(a[i],ma);
}
if(sum+k>=ma*n){
cout<<ma+((sum+k)-ma*n)/n<<endl;
return 0;
}
for(int i=1;i<=ma;i++){
num[i]=num[i-1]+num[i];
}
for(int i=ma;i>=1;i--){
int cnt=0;
for(int j=1;j*i<=ma*2 && i*(j-1)<=ma;j++){
cnt+=(num[min(ma,i*j)]-num[i*(j-1)])*i*j;
}
int xq=cnt-sum;
if(xq<=k){
cout<<i<<" ";
return 0;
}
}
}
连续子段#
设
思考两种点:
关键点:最终为连续子段,贡献为当前点对
非关键点:最终不为连续子段、贡献为
转移时,每个点都可以为非,但是并不是都可以为关键点
可以滚掉一维,但循环顺序要改变,避免更新重复。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a[202];
int dp[65540];
int num[65540];
signed main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int t=(1<<k);
for(int i=0;i<=t;i++){
num[i]=__builtin_popcount(i);
}
memset(dp,0x7f,sizeof(dp));
dp[0]=0;
int ma=(1<<30);
for(int i=1;i<=n;i++){
for(int s=t-1;s>=0;s--){
int cnt=__builtin_popcount(s);
if(!(s&(1<<(a[i]-1)))){
dp[s|(1<<(a[i]-1))]=min(dp[s|(1<<(a[i]-1))],dp[s]+num[s>>a[i]<<a[i]]);
}
dp[s]+=min(cnt,k-cnt);
}
}
cout<<dp[t-1];
}
csp模拟8#
Coprime 2#
考场上想到一个60分的暴力,就是把所有的
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2000005;
int a[N],b[N],c[N];
int n,m;
int ans[N];
bool ask[N+10],flat[N+10];
void getphi(){
ans[++ans[0]]=1;
for(int i=2;i<=m;i++){
int op=0;
if(!flat[i]){
for(int j=2;i*j<=m;j++){
flat[i*j]=1;
if(b[i*j]) op=1;
}
if(op){
for(int j=2;i*j<=m;j++){
c[i*j]=1;
}
}
}
if(!b[i] && !op && !c[i]) ans[++ans[0]]=i;
}
}
signed main(){
memset(b,0,sizeof(b));
memset(ask,0,sizeof(ask));
memset(flat,0,sizeof(flat));
memset(c,0,sizeof(c));
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[a[i]]=1;
}
getphi();
cout<<ans[0]<<endl;
for(int i=1;i<=ans[0];i++){
printf("%lld\n",ans[i]);
}
}
Dist Max 2#
考场上只写出一个
一眼就可以看出是二分,但是如何查找,是个问题。
这就要引用学长的话:"遇事不决就排序"。
所以按照左端点进行排序,维护一个双指针
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int M=1e9+10;
struct asd{
int x,y;
}a[N];
int n;
int maq[N],miq[N],mah[N],mih[N];
bool amp(asd a,asd b){
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
int check(int d){
for(int i=1,j=1;i<=n;i++){
while(j<n && (a[j].x-a[i].x)<d) j++;
if((a[j].x-a[i].x)>=d){
if((mah[j]-miq[i])>=d || (maq[i]-mih[j])>=d) return 1;
}
}
return 0;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
}
sort(a+1,a+n+1,amp);
maq[1]=a[1].y;
miq[1]=a[1].y;
for(int i=2;i<=n;i++){
maq[i]=max(maq[i-1],a[i].y);
miq[i]=min(miq[i-1],a[i].y);
}
mah[n]=a[n].y;
mih[n]=a[n].y;
for(int i=n-1;i>=1;i--){
mah[i]=max(mah[i+1],a[i].y);
mih[i]=min(mih[i+1],a[i].y);
}
int l=0,r=M;
while(l<r){
int mid=(l+r+1)/2;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
Count Multiset#
考场上不会。
有一种很神奇的转移,就是加一加零,我感觉就是方便转移,或者是因为可以看成单调递增序列,所以进行排序后是一样的。
但是每个数有限制,所以零不能无限制的加,所以设
转移就出来了:
可以进行前缀和优化,复杂度
暴力代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int f[5005][5005];
int g[5005][5005];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
if(i<=m) f[i][0]=1;
for(int j=1;j<=n;j++){
int ans=0;
for(int k=1;k<=m;k++){
if(i>=k)
ans=(ans+g[i-k][j])%mod;
}
f[i][j]=(f[i][j]+ans)%mod;
if(j>=i)
f[i][j]=(f[i][j]+f[i][j-i])%mod;
if(j>=i)
g[i][j]=f[i][j-i];
}
}
for(int i=1;i<=n;i++){
cout<<g[i][n]<<endl;
}
}
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int f[5005][5005];
int g[5005][5005];
int sum[5005][5005];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
if(i<=m) f[i][0]=1;
for(int j=1;j<=n;j++){
int ans=0;
ans=(sum[i-1][j]-sum[i-m-1][j]+mod)%mod;
f[i][j]=(f[i][j]+ans)%mod;
if(j>=i) f[i][j]=(f[i][j]+f[i][j-i])%mod;
if(j>=i) sum[i][j]=(sum[i][j]+f[i][j-i])%mod;
sum[i][j]=(sum[i][j]+sum[i-1][j])%mod;
}
}
for(int i=1;i<=n;i++){
cout<<f[i][n-i]<<endl;
}
}
Julia the snail#
考试是打的
吉司机线段树:
吉司机线段树上的叶子结点
考虑将所有的询问按照右端点从小到大排序。我们维护一个指针
对于指针移动过程中遇到的所有
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
const int inf=1e7;
struct asd{
int l,r,ans,id;
}b[N],c[N];
struct qwe{
int l,r,fir,sec,lazy1,lazy2;
}tr[N*4];
int pre[N];
int ans[N];
int n,m;
bool amp(asd a,asd b){
return a.r<b.r;
}
void pushup(int p){//合并左右子树
if(tr[p*2].fir==tr[p*2+1].fir){
tr[p].fir=tr[p*2].fir;
tr[p].sec=max(tr[p*2].sec,tr[p*2+1].sec);
}
else if(tr[p*2].fir<tr[p*2+1].fir){
tr[p].fir=tr[p*2+1].fir;
tr[p].sec=max(tr[p*2].fir,tr[p*2+1].sec);
}
else{
tr[p].fir=tr[p*2].fir;
tr[p].sec=max(tr[p*2].sec,tr[p*2+1].fir);
}
}
void push(int p,int s1,int s2){//更改延迟标记 ,这里的情况还要考虑普通的延迟标记下放
if(tr[p].fir<s1) return;
tr[p].fir=s2;
tr[p].lazy1=min(tr[p].lazy1,s1);
tr[p].lazy2=s2;
}
void pushdown(int p){//下传延迟标记
if(tr[p].lazy1!=inf){
push(p*2,tr[p].lazy1,tr[p].lazy2);
push(p*2+1,tr[p].lazy1,tr[p].lazy2);
tr[p].lazy1=tr[p].lazy2=inf;
}
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
tr[p].lazy1=tr[p].lazy2=inf;
if(l==r){
tr[p].fir=l;
tr[p].sec=-1;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void change(int p,int l,int r,int s1,int s2){
if(tr[p].fir<s1) return;//当前节点不符合更新条件
if(tr[p].l>=l && tr[p].r<=r && s1>tr[p].sec){//要大于次大值,进行不断递归
push(p,s1,s2);
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change(p*2,l,r,s1,s2);
if(r>mid) change(p*2+1,l,r,s1,s2);
pushup(p);
}
int ask(int p,int wh){
if(tr[p].l==tr[p].r) return tr[p].fir;
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) return ask(p*2,wh);
return ask(p*2+1,wh);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&b[i].l,&b[i].r);
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d",&c[i].l,&c[i].r);
c[i].id=i;
}
sort(c+1,c+q+1,amp);
sort(b+1,b+m+1,amp);
build(1,1,n);
int op=1;
for(int i=1;i<=q;i++){
while(b[op].r<=c[i].r && op<=m){
change(1,1,b[op].l,b[op].l,b[op].r);op++;
}
ans[c[i].id]=ask(1,c[i].l);
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
}
/*
8
4
1 2
3 4
2 5
6 7
5
1 2
1 4
1 6
2 7
6 8
*/
csp模拟6#
排序#
首先找到所有的逆序对,前提是所有的逆序对都要用到,在考虑从大往小替换,思考
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a[1005];
int pos[1005];
struct asd{
int x,y;
}b[1005];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[a[i]]=i;
}
int cnt=0;
for(int i=2;i<=n;i++){
for(int j=i-1;j>=1;j--){
if(a[j]>a[i]){
cnt++;
}
}
}
cout<<cnt<<endl;
for(int i=n;i>=1;i--){
for(int j=a[i]+1;j<=i;j++){
cout<<pos[j]<<" "<<i<<endl;
swap(a[pos[j]],a[i]);
pos[j-1]=pos[j];
pos[j]=i;
}
}
}
/*
10
2 6 8 5 3 7 4 10 9 1
*/
无聊的卡牌问题#
我们可以首先处理出来哪几张牌为一组,可以通过一个栈处理出来,然后再跑一遍栈,处理出来先后关系,具体操作就是从
之后就跑拓扑,考虑当先所需的为先手方还是后手方,用异或转移,还有要有叶子节点先取叶子节点(注意独立点不是叶子节点),没有的情况下再取独立店,而且叶子节点数量要区分先后手。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2000;
int a[N],b[N];
int flat[N];
int sy[N],rk[N];
int head[N*2],ver[N*2],nex[N*2],tot=0;
struct asd{
int x,y,z;
}tr[N];
void add(int x,int y){
ver[++tot]=y;nex[tot]=head[x];head[x]=tot;
}
int s[N];
int rd[N],cd[N];
queue<int>q;
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n*3;i++){
scanf("%d",&a[i]);
flat[a[i]]=1;
}
int fk=0;
int sum=0;
int top=0;
for(int i=1;i<=n*6;i++){
s[++top]=i;
if(top>=3){
if(top && flat[s[top]]==flat[s[top-1]] && flat[s[top]]==flat[s[top-2]]){
tr[++sum]={s[top-2],s[top-1],s[top]};
sy[s[top-2]]=sy[s[top-1]]=sy[s[top]]=sum;
rk[sum]=flat[s[top]];
top-=3;
}
}
}
for(int i=1;i<=n*6;i++){
s[++top]=i;
if(top>=3){
if(top && flat[s[top]]==flat[s[top-1]] && flat[s[top-1]]==flat[s[top-2]]){
if(top-3>0){
add(sy[s[top]],sy[s[top-3]]);
rd[sy[s[top-3]]]++;
cd[sy[s[top]]]++;
}
top-=3;
}
}
}
bool nm[N];
int left[2]={0,0};
for(int i=1;i<=sum;i++){
nm[i]=0;
if(!rd[i]){
if(cd[i]){
left[rk[i]]++;
nm[i]=1;
}
q.push(i);
}
}
int w=1;
while(!q.empty()){
int x=q.front();
q.pop();
while(rk[x]!=w ||( left[w] && !nm[x])){
q.push(x);
x=q.front();
q.pop();
}
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
rd[y]--;
if(rd[y]==0){
if(cd[y]){
left[rk[y]]++;
nm[y]=1;
}
q.push(y);
}
}
if(nm[x]) left[rk[x]]--;
printf("%d %d %d\n",tr[x].x,tr[x].y,tr[x].z);
w^=1;
}
}
csp模拟9#
最短路#
考虑给
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=305;
int n,m,Q;
struct asd{
int d,id;
}a[N];
int f[N][N];
int g[N][N],ma[N][N];
int mp[N];
int amp(asd a,asd b){
return a.d<b.d;
}
signed main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&Q);
memset(f,0x3f,sizeof(f));
memset(g,0x3f,sizeof(g));
for(int i=1;i<=n;i++){
scanf("%lld",&a[i].d);
a[i].id=i;
}
sort(a+1,a+n+1,amp);
for(int i=1;i<=n;i++){
mp[a[i].id]=i;
}
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
f[mp[x]][mp[y]]=f[mp[y]][mp[x]]=min(f[mp[x]][mp[y]],z);
}
for(int i=0;i<=n;i++){
f[i][i]=0;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
g[i][j]=min(g[i][j],f[i][j]+max(a[i].d,max(a[j].d,a[k].d)));
}
}
}
for(int i=1;i<=Q;i++){
int x,y;
scanf("%lld%lld",&x,&y);
if(g[mp[x]][mp[y]]>1e12){
cout<<"-1"<<endl;
}
else{
cout<<g[mp[x]][mp[y]]<<endl;
}
}
}
/*
4 5 3
2 4 4 5
2 3 3
4 1 5
4 2 5
1 2 1
3 2 2
3 2
2 1
4 3
6
5
12
*/
方格取数#
考场上想到的是二分套二分,得到
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
int n,k;
int a[N][N];
int sum[N][N];
int ask(int x,int y,int x1,int y1){
int ans=sum[x1][y1]-sum[x1][y-1]-sum[x-1][y1]+sum[x-1][y-1];
return ans;
}
int check(int x,int y,int x1){
if(ask(x,y,x1,y)>2*k){
return 0;
}
int l=y-1,r=n+1;
while(l<r){
int mid=(l+r+1)/2;
int cnt=ask(x,y,x1,mid);
if(cnt<k) l=mid;
else if(cnt>k*2) r=mid-1;
else{
printf("%lld %lld %lld %lld",x,y,x1,mid);
exit(0);
}
}
if(l<=y) return 0;
else return 1;
}
signed main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%lld%lld",&n,&k);
int opt=0;
int x1,x2,y1,y2,fk=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]);
if(a[i][j]>=k && a[i][j]<=k*2){
fk=1;
x1=i,x2=i,y1=j,y2=j;
}
if(a[i][j]<k) opt=1;
}
}
if(fk==1){
cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
return 0;
}
if(opt==0){
cout<<"-1"<<endl;
return 0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ask(i,j,i,j)>k*2){
continue;
}
int l=i-1,r=n+1;
while(l<r){
int mid=(l+r+1)/2;
if(check(i,j,mid)) l=mid;
else r=mid-1;
}
}
}
cout<<"-1"<<endl;
}
/*
3 5
6 15 5
11 6 6
11 6 6
3 5
4 15 3
11 3 4
11 1 1
2 2 3 3
*/
数组#
真的很巧妙,因为
剩下的就是维护一个线段树,维护区间的乘积以及区间所包含的质数。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
int a[N],w[N];
int inv[N];
int prime[100];
bool nprime[N];
int mp[N];
struct asd{
int l,r,val,lazy1,zt,lazy2;
asd(){
val=1ll,lazy1=1ll,lazy2=0,zt=0;
}
}tr[N*4];
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
void work(){
for(int i=2;i<=300;++i){
if(!nprime[i]){
prime[++prime[0]]=i;
}
for(int j=1;j<=prime[0] && i*prime[j]<=300;++j){
int k=i*prime[j];
nprime[k]=1;
if(i%prime[j]==0) break;
}
}
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
if(l==r){
tr[p].val=a[l];
tr[p].zt=w[l];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p].val=tr[p*2].val*tr[p*2+1].val%mod;
tr[p].zt=tr[p*2].zt|tr[p*2+1].zt;
}
void pushdown(int p){
if(tr[p].lazy1 || tr[p].lazy2){
tr[p*2].lazy1=tr[p*2].lazy1*tr[p].lazy1%mod;
tr[p*2].val=tr[p*2].val*mgml(tr[p].lazy1,tr[p*2].r-tr[p*2].l+1)%mod;
tr[p*2+1].lazy1=tr[p*2+1].lazy1*tr[p].lazy1%mod;
tr[p*2+1].val=tr[p*2+1].val*mgml(tr[p].lazy1,tr[p*2+1].r-tr[p*2+1].l+1)%mod;
tr[p].lazy1=1;
tr[p*2].lazy2|=tr[p].lazy2;
tr[p*2].zt|=tr[p*2].lazy2;
tr[p*2+1].lazy2|=tr[p].lazy2;
tr[p*2+1].zt|=tr[p*2+1].lazy2;
tr[p].lazy2=0;
}
}
asd ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r){
return tr[p];
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
asd x,y,z;
x.val=y.val=1;
if(l<=mid) x=ask(p*2,l,r);
if(r>mid) y=ask(p*2+1,l,r);
z.val=x.val*y.val%mod;
z.zt=x.zt|y.zt;
return z;
}
void change(int p,int l,int r,int v,int z){
if(tr[p].l>=l && tr[p].r<=r){
tr[p].lazy1=(tr[p].lazy1*v)%mod;
tr[p].val=tr[p].val*mgml(v,tr[p].r-tr[p].l+1)%mod;
tr[p].lazy2|=z;
tr[p].zt|=z;
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) change(p*2,l,r,v,z);
if(r>mid) change(p*2+1,l,r,v,z);
tr[p].val=tr[p*2].val*tr[p*2+1].val%mod;
tr[p].zt=tr[p*2].zt|tr[p*2+1].zt;
}
signed main(){
freopen("array.in","r",stdin);
freopen("array.out","w",stdout);
int n,q;
work();
for(int i=1;i<=prime[0];++i){
mp[prime[i]]=i;
inv[prime[i]]=mgml(prime[i],mod-2);
}
n=read(),q=read();
// scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;++i){
a[i]=read();
// scanf("%lld",&a[i]);
int tmp=a[i];
for(int j=2;j<=tmp;j++){
if(tmp%j==0){
w[i]|=(1ll<<(mp[j]-1ll));
while(tmp%j==0){
tmp/=j;
}
}
}
}
build(1,1,n);
for(int i=1;i<=q;i++){
int op;
op=read();
if(op==2){
int x,y;
x=read(),y=read();
asd s;
s=ask(1,x,y);
int ans1=s.val,ans2=s.zt;
for(int j=1;j<=62;j++){
if(ans2&(1ll<<(j-1ll))){
ans1=ans1*(prime[j]-1)%mod*inv[prime[j]]%mod;
}
}
cout<<ans1<<endl;
}
else{
int x,y,z;
x=read(),y=read(),z=read();
int tmp=z,fk=0;
for(int i=2;i<=tmp;i++){
if(tmp%i==0){
fk|=(1ll<<(mp[i]-1ll));
while(tmp%i==0){
tmp/=i;
}
}
}
change(1,x,y,z,fk);
}
}
}
/*
4 4
2 4 6 7
2 1 4
1 2 3 3
1 3 4 4
2 3 4
2 12 72 28
96
576
*/
树#
考场上打的暴力和部分分,可以拿
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int tp[N][240];
int a[N],b[N],c[N];
int head[N*2],nex[N*2],ver[N*2],fa[N],tot=0;
int f[N][40];
int d[N];
int n;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
}
void dfs(int x,int far){
fa[x]=far;
d[x]=d[far]+1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==far) continue;
f[y][0]=x;
dfs(y,x);
}
}
void init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=30;j++){
f[i][j]=f[f[i][j-1]][j-1];
}
}
}
int ask_lca(int x,int y){
if(d[x]<d[y]) swap(x,y);
for(int i=16;i>=0;i--){
if(d[f[x][i]]>=d[y]) x=f[x][i];
}
if(x==y) return x;
for(int i=16;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
int geten(int x,int k){
for(int i=16;i>=0;i--){
if(k>=(1<<i)){
k-=(1<<i);
x=f[x][i];
}
}
return x;
}
int get(int x,int y,int fk){
int lca=ask_lca(x,y);
int ans=0;
while(d[x]>d[lca]){
ans+=a[x];
x=geten(x,fk);
}
while(d[y]>=d[lca]){
ans+=a[y];
y=geten(y,fk);
}
return ans;
}
void dfs1(int x,int t){
for(int i=1;i<=t;i++){
tp[x][i]=tp[geten(x,i)][i]+a[x];
}
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa[x]) continue;
dfs1(y,t);
}
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d",&n);
int t=sqrt(n);
int op=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int op1=0;
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs(1,0);
init();
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
for(int i=1;i<n;i++){
scanf("%d",&c[i]);
}
dfs1(1,t);
// for(int i=1;i<=n;i++){
// cout<<tp[i][1]<<endl;
// }
for(int i=1;i<n;i++){
int x=b[i],y=b[i+1];
if(c[i]>=t){
printf("%d\n",get(x,y,c[i]));
}
else{
int k=c[i];
int lca=ask_lca(x,y);
int ans=tp[x][k]+tp[y][k];
int tmp=lca;
while((d[x]-d[tmp])%k!=0 && tmp){
tmp=fa[tmp];
}
ans-=tp[tmp][k];
tmp=lca;
while((d[y]-d[tmp])%k!=0 && tmp){
tmp=fa[tmp];
}
ans-=tp[tmp][k];
if(tmp==lca) ans+=a[lca];
printf("%d\n",ans);
}
}
}
/*
8
1 4 5 5 2 1 4 5
1 2
2 3
1 4
4 5
1 6
5 7
5 8
5 2 7 3 1 6 8 4
3 4 1 1 1 4 2
6
8
21
10
2
6
10
*/
csp模拟10#
U#
考场上想的是暴力,就是
对于
对于
边,对于这种情况可以通过存权值为
有权值为
设
设
之后求
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int N=2*1e5+10;
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
int f[N],inv[N];
void init(){
f[0]=1;
inv[0]=1;
for(int i=1;i<=N;i++){
f[i]=f[i-1]*i%mod;
inv[i]=mgml(f[i],mod-2);
}
}
int c(int x,int y){
return f[x]*inv[x-y]%mod*inv[y]%mod;
}
int ans[N];
int e[N];
int head[N*2],ver[N*2],nex[N*2],edge[N*2],tot=0;
void add(int x,int y,int v){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot,edge[tot]=v;
ver[++tot]=x,nex[tot]=head[y],head[y]=tot,edge[tot]=v;
}
int size[N],fa[N];
int far[N];
int top[N];
int sum[N],cnt[N],zong[N];
void dfs(int x){
size[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa[x]) continue;
e[y]=edge[i];
fa[y]=x;
dfs(y);
size[x]+=size[y];
}
sum[x]=size[x];
}
void dfs1(int x){
top[x]=far[e[x]];
far[e[x]]=x;
sum[top[x]]-=sum[x];
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa[x]) continue;
dfs1(y);
}
far[e[x]]=top[x];
}
int data=0;
signed main(){
int n;
scanf("%lld",&n);
int op1=0;
for(int i=1;i<n;i++){
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add(x,y,z);
}
init();
dfs(1);
dfs1(1);
for(int i=1;i<=n;i++){
zong[e[i]]+=sum[i];
}
for(int i=1;i<=n;i++){
if(top[i]){
cnt[i]=sum[top[i]];
}
else{
cnt[i]=size[1]-zong[e[i]];
}
}
for(int i=1;i<=n;i++){
data+=sum[i]*cnt[i]%mod;
data%=mod;
}
for(int k=2;k<=n;k++){
ans[k]=c(n-2,k-2)*data%mod*mgml(c(n,k),mod-2)%mod;
}
int lhxshishen=0;
for(int i=1;i<=n;i++){
lhxshishen^=ans[i];
}
cout<<lhxshishen<<endl;
return 0;
}
/*
5
1 2 1
1 3 2
2 4 2
4 5 1
2
1 2 1
3
1 2 1
1 3 2
*/
E#
暴力+线段树
每个点开一个
以两个区间为例,
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
struct asd{
int l,r;
}a[N];
struct qwe{
int l,r;
}tr[N*4];
struct zxc{
int l,r;
};
vector<zxc> s[N*4];
zxc b[N*4];
zxc dl;
bool amp(zxc a,zxc b){
if(a.l==b.l) return a.r<b.r;
return a.l<b.l;
}
vector<zxc> qc(vector<zxc> k){
int len=k.size();
if(k.empty()) return k;
for(int i=0;i<len;i++){
b[i+1].l=k[i].l;
b[i+1].r=k[i].r;
}
vector<zxc> w;
w.clear();
sort(b+1,b+len+1,amp);
w.push_back(dl);
int num=0;
for(int i=1;i<=len;i++){
if(b[i].l>w[num].r+1){
num++;
w.push_back(b[i]);
}
else if(b[i].r>w[num].r){
w[num].r=b[i].r;
}
}
return w;
}
vector<zxc> merge(vector<zxc> s1,vector<zxc> s2){
if(s1.empty()) return s2;
vector<zxc> w;
w.clear();
for(int i=0;i<s1.size();i++){
for(int j=0;j<s2.size();j++){
zxc s3;
s3.l=s1[i].l+s2[j].l;
s3.r=s1[i].r+s2[j].r;
w.push_back(s3);
}
}
w=qc(w);
return w;
}
void build(int p,int l,int r){
s[p].push_back(dl);
tr[p].l=l,tr[p].r=r;
if(l==r){
zxc fk;
fk.l=a[l].l,fk.r=a[l].r;
s[p].push_back(fk);
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
s[p]=merge(s[p*2],s[p*2+1]);
}
void change(int p,int wh,int l,int r){
if(tr[p].l==tr[p].r){
zxc fk;
fk.l=l,fk.r=r;
s[p].clear();
s[p].push_back(dl);
s[p].push_back(fk);
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) change(p*2,wh,l,r);
else change(p*2+1,wh,l,r);
s[p]=merge(s[p*2],s[p*2+1]);
}
vector<zxc> ans;
void ask(int p,int l,int r){
if(tr[p].l>=l &&tr[p].r<=r){
ans=merge(ans,s[p]);
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) ask(p*2,l,r);
if(r>mid) ask(p*2+1,l,r);
}
signed main(){
dl.l=0,dl.r=0;
int n,q;
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&a[i].l,&a[i].r);
}
build(1,1,n);
for(int i=1;i<=q;i++){
int op;
scanf("%lld",&op);
if(op==2){
int x,y;
scanf("%lld%lld",&x,&y);
ans.clear();
ask(1,x,y);
ans=qc(ans);
int lhx=0;
for(int j=0;j<ans.size();j++){
lhx+=ans[j].r-ans[j].l+1;
}
printf("%lld\n",lhx);
}
else{
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
change(1,x,y,z);
}
}
}
**都看到这了,还不点个赞。**
/*
3 5
2 3
1 1
3 4
2 1 1
2 1 2
2 1 3
1 2 1 5
2 1 3
*/
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,R,P;
int dp[215][215][25][25];
int v[250],a[250];
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=ans*x;
x=x*x;
p>>=1;
}
return ans;
}
int val(int x,int k){
return v[k]*mgml(P,x-1);
}
void solve(int l,int r){
for(int k=1;k<=m;k++){
for(int i=l;i<=r;i++){
if(a[i]==k){
dp[l][r][1][k]=max(dp[l][r][1][k],dp[l][i-1][0][0]+dp[i+1][r][0][0]);
}
}
}
for(int x=2;x<=R;x++){
for(int k=1;k<=m;k++){
for(int i=l;i<=r;i++){
dp[l][r][x][k]=max(dp[l][r][x][k],dp[l][i][x-1][k]+dp[i+1][r][x-1][k]);
}
}
}
int res1=0,res2=0;
for(int i=l;i<=r-1;i++){
res1=max(res1,dp[l][i][0][0]+dp[i+1][r][0][0]);
}
for(int x=1;x<=R;x++){
for(int k=1;k<=m;k++){
res2=max(res2,dp[l][r][x][k]+val(x,k));
}
}
dp[l][r][0][0]=max(res1,res2);
}
signed main(){
for(int i=0;i<=210;i++){
for(int j=0;j<=210;j++){
for(int k=1;k<=22;k++){
for(int l=1;l<=22;l++){
dp[i][j][k][l]=-1145141919280;
}
}
}
}
scanf("%lld%lld%lld%lld",&n,&m,&R,&P);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%lld",&v[i]);
}
for(int len=1;len<=n;len++){
for(int l=1,r=l+len-1;r<=n;l++,r++){
solve(l,r);
}
}
cout<<dp[1][n][0][0]<<endl;
}
/*
7 3 4 3
1 3 2 3 2 3 3
1 2 3
*/
**都看到这了,还不点个赞。**
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5005;
const int mod=998244353;
int n;
int dp[N][N][2];
int s[N];
int jc[N];
void init(){
jc[0]=1;
for(int i=1;i<=n+10;i++){
jc[i]=jc[i-1]*i%mod;
}
}
signed main(){
scanf("%lld",&n);
int op=0;
for(int i=1;i<n;i++){
scanf("%lld",&s[i]);
}
dp[1][0][0]=dp[1][1][1]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<=i;j++){
if(s[i-1]){
dp[i][j][0]+=dp[i-1][j][0];
dp[i][j][1]+=dp[i-1][j][1];//此位为0
if(j>0){
dp[i][j][1]+=dp[i-1][j-1][0]+dp[i-1][j-1][1];//此位为1
}
}
else{
dp[i][j][0]+=dp[i-1][j][0]+dp[i-1][j][1];//此为为0
if(j>0){
dp[i][j][1]+=dp[i-1][j-1][1];
dp[i][j][0]+=dp[i-1][j-1][0];
}
}
dp[i][j][0]%=mod;
dp[i][j][1]%=mod;
}
}
init();
int ans=0;
for(int i=1;i<=n;i++){
int sum=(dp[n][i][1]*jc[i]%mod*jc[n-i]%mod+mod-dp[n][i-1][1]*jc[i-1]%mod*jc[n-i+1]%mod)%mod*(n-i+1)%mod;
ans+=sum;
ans%=mod;
}
printf("%lld",ans);
}
csp模拟13#
s#
如果这个理解不了你还可以这样计算答案,
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5005;
const int mod=998244353;
int n;
int dp[N][N][2];
int s[N];
int jc[N];
void init(){
jc[0]=1;
for(int i=1;i<=n+10;i++){
jc[i]=jc[i-1]*i%mod;
}
}
signed main(){
scanf("%lld",&n);
int op=0;
for(int i=1;i<n;i++){
scanf("%lld",&s[i]);
}
dp[1][0][0]=dp[1][1][1]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<=i;j++){
if(s[i-1]){
dp[i][j][0]+=dp[i-1][j][0];
dp[i][j][1]+=dp[i-1][j][1];//此位为0
if(j>0){
dp[i][j][1]+=dp[i-1][j-1][0]+dp[i-1][j-1][1];//此位为1
}
}
else{
dp[i][j][0]+=dp[i-1][j][0]+dp[i-1][j][1];//此为为0
if(j>0){
dp[i][j][1]+=dp[i-1][j-1][1];
dp[i][j][0]+=dp[i-1][j-1][0];
}
}
dp[i][j][0]%=mod;
dp[i][j][1]%=mod;
}
}
init();
int ans=0;
for(int i=1;i<=n;i++){
int sum=(dp[n][i][1]*jc[i]%mod*jc[n-i]%mod+mod-dp[n][i-1][1]*jc[i-1]%mod*jc[n-i+1]%mod)%mod*(n-i+1)%mod;
ans+=sum;
ans%=mod;
}
printf("%lld",ans);
}
p#
然后就是进行线段树维护一个区间的左右树的直径的两个端点,合并时考虑六种情况,注意赋初值。
这里做一下引流
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+10;
int head[N*2],ver[N*2],nex[N*2],tot=0;
void add(int x,int y){
ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
ver[++tot]=x,nex[tot]=head[y],head[y]=tot;
}
int fa[N],top[N],size[N],d[N],son[N];
void dfs1(int x,int f){
d[x]=d[f]+1;
fa[x]=f;
size[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==f) continue;
dfs1(y,x);
size[x]+=size[y];
if(size[son[x]]<size[y]){
son[x]=y;
}
}
}
void dfs2(int x,int tp){
top[x]=tp;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=nex[i]){
int y=ver[i];
if(y==fa[x]) continue;
if(y!=son[x]) dfs2(y,y);
}
}
int ask_lca(int x,int y){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(d[fx]>d[fy]){
x=fa[fx],fx=top[x];
}
else{
y=fa[fy],fy=top[y];
}
}
if(d[x]<d[y]) return x;
else return y;
}
struct asd{
int l,r,ls,rs,sum;
}tr[N*4];
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
tr[p].ls=tr[p].rs=0;
if(l==r){
tr[p].ls=tr[p].rs=0;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
asd jjq(asd s1,asd s2){
int id1=0,id2=0;
int dis=-1;
asd z;
if(s1.ls && s2.ls){
int lca=ask_lca(s1.ls,s2.ls);
int dist=d[s1.ls]+d[s2.ls]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s1.ls,id2=s2.ls;
}
}
if(s1.rs && s2.rs){
int lca=ask_lca(s1.rs,s2.rs);
int dist=d[s1.rs]+d[s2.rs]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s1.rs,id2=s2.rs;
}
}
if(s1.ls && s1.rs){
int lca=ask_lca(s1.ls,s1.rs);
int dist=d[s1.ls]+d[s1.rs]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s1.ls,id2=s1.rs;
}
}
if(s2.ls && s2.rs){
int lca=ask_lca(s2.ls,s2.rs);
int dist=d[s2.ls]+d[s2.rs]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s2.ls,id2=s2.rs;
}
}
if(s1.ls && s2.rs){
int lca=ask_lca(s1.ls,s2.rs);
int dist=d[s1.ls]+d[s2.rs]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s1.ls,id2=s2.rs;
}
}
if(s1.rs && s2.ls){
int lca=ask_lca(s1.rs,s2.ls);
int dist=d[s1.rs]+d[s2.ls]-2*d[lca];
if(dis<dist){
dis=dist;
id1=s1.rs,id2=s2.ls;
}
}
z.ls=id1,z.rs=id2;
z.l=s1.l,z.r=s2.r;
z.sum=s1.sum+s2.sum;
return z;
}
void change(int p,int wh){
if(tr[p].l==tr[p].r){
tr[p].sum^=1;
if(tr[p].sum){
tr[p].ls=tr[p].rs=tr[p].l;
}
else{
tr[p].ls=tr[p].rs=0;
}
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) change(p*2,wh);
else change(p*2+1,wh);
tr[p]=jjq(tr[p*2],tr[p*2+1]);
}
asd ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r) return tr[p];
int mid=(tr[p].l+tr[p].r)/2;
asd s1,s2,s3;
s1.sum=0,s1.ls=0,s1.rs=0,s2.ls=0,s2.rs=0,s2.sum=0;
s1.l=s1.r=s2.l=s2.r=0;
if(l<=mid) s1=ask(p*2,l,r);
if(r>mid) s2=ask(p*2+1,l,r);
s3=jjq(s1,s2);
return s3;
}
int ask_sum(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r) return tr[p].sum;
int mid=(tr[p].l+tr[p].r)/2;
int ans=0;
if(l<=mid) ans+=ask_sum(p*2,l,r);
if(r>mid) ans+=ask_sum(p*2+1,l,r);
return ans;
}
signed main(){
int n,m;
int op1=0;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op==1){
int x;
scanf("%d",&x);
change(1,x);
}
else{
int l,r;
scanf("%d%d",&l,&r);
asd s=ask(1,l,r);
int lca=ask_lca(s.ls,s.rs);
int ans=ask_sum(1,l,r);
if(ans==0){
cout<<"-1"<<endl;
continue;
}
if(ans==1){
cout<<"0"<<endl;
continue;
}
printf("%d\n",d[s.ls]+d[s.rs]-2*d[lca]);
}
}
}
/*
5 5
1 2
1 3
3 4
3 5
1 1
1 3
2 4 5
1 4
2 1 4
*/
m#
然后进行预处理卡时间卡空间,还有朱老师介绍的光速幂,复杂度预处理
csp模拟12#
便#
这道题思想很不错,利用线段树维护转移矩阵,感觉官方题解很详细
还有就是各种优化,比如实际矩阵是一个三角矩阵,所以优化一半。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int mod=1e9+7;
inline int read(){
int x(0);bool f(0);char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) f^=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return f?x=-x:x;
}
inline void write(int x){
x<0?x=-x,putchar('-'):0;static short Sta[50],top(0);
do{Sta[++top]=x%10;x/=10;}while(x);
while(top) putchar(Sta[top--]|48);
putchar('\n');
}
int n,a[N];
struct asd{
int l,r;
}tr[N*4];
struct qwe{
int l,r,s[12][12];
}t[N*4];
int sum=0,ny;
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
qwe mul(qwe s1,qwe s2){
qwe z;
memset(z.s,0,sizeof(z.s));
z.l=s1.r;
z.r=s2.l;
for(int i=1;i<=s1.r;++i){
for(int j=1;j<=s2.l;++j){
int mi=min(s1.l,j);
for(int k=i;k<=mi;++k){
z.s[j][i]+=s1.s[k][i]*s2.s[j][k];
}
z.s[j][i]%=mod;
}
}
return z;
}
void build(int p,int l,int r){
tr[p].l=l,tr[p].r=r;
t[p].l=11,t[p].r=11;
if(l==r){
for(int i=1;i<=11;++i){
t[p].s[i][i]=1;
}
t[p].s[2][1]=a[1];
t[p].s[3][2]=a[2];
t[p].s[4][3]=t[p].s[5][4]=t[p].s[10][9]=a[3];
t[p].s[6][5]=t[p].s[8][7]=a[4];
t[p].s[7][6]=a[5];
t[p].s[9][8]=a[6];
t[p].s[11][10]=a[7];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p]=mul(t[p*2],t[p*2+1]);
}
void change(int p,int wh,char s){
if(tr[p].l==tr[p].r){
memset(t[p].s,0,sizeof(t[p].s));
t[p].l=t[p].r=11;
for(int i=1;i<=11;++i){
t[p].s[i][i]=1;
}
if(s=='h') t[p].s[2][1]=1;
if(s=='e') t[p].s[3][2]=1;
if(s=='l') t[p].s[4][3]=t[p].s[5][4]=t[p].s[10][9]=1;
if(s=='o') t[p].s[6][5]=t[p].s[8][7]=1;
if(s=='w') t[p].s[7][6]=1;
if(s=='r') t[p].s[9][8]=1;
if(s=='d') t[p].s[11][10]=1;
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(wh<=mid) change(p*2,wh,s);
else change(p*2+1,wh,s);
t[p]=mul(t[p*2],t[p*2+1]);
}
qwe kkk;
void ask(int p,int l,int r){
if(tr[p].l>=l && tr[p].r<=r){
kkk=mul(kkk,t[p]);
return;
}
int mid=(tr[p].l+tr[p].r)/2;
if(l<=mid) ask(p*2,l,r);
if(r>mid) ask(p*2+1,l,r);
return;
}
signed main(){
n=read();
for(int i=1;i<=7;++i){
a[i]=read();
sum=(sum+a[i])%mod;
}
ny=mgml(sum,mod-2);
for(int i=1;i<=7;++i){
a[i]=a[i]*ny%mod;
}
build(1,1,n);
int q;
q=read();
for(int i=1;i<=q;++i){
int op;
op=read();
if(op==1){
int wh;
char s;
wh=read();
cin>>s;
change(1,wh,s);
}
else{
int l,r;
l=read(),r=read();
qwe hx;
memset(hx.s,0,sizeof(hx.s));
hx.l=11,hx.r=1;
hx.s[1][1]=1;
memset(kkk.s,0,sizeof(kkk.s));
kkk.l=kkk.r=11;
for(int l=1;l<=11;l++){
kkk.s[l][l]=1;
}
ask(1,l,r);
hx=mul(hx,kkk);
write(hx.s[11][1]);
}
}
}
/*
11
1 1 1 1 1 1 1
16
1 1 h
2 2 11
2 2 11
1 2 e
1 3 l
1 4 l
1 5 l
2 1 11
1 6 o
1 7 w
2 2 11
1 8 o
1 9 r
1 10 l
1 11 d
2 1 11
*/
csp模拟15#
Team Work#
先学斯特林数
注意分情况求解。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+10;
const int mod=1e9+7;
int n,k;
int s2[5005][5005];
int f[N],inv[N];
int base[N];
int mgml(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
int c(int x,int y){
int ans=1;
for(int i=y+1;i<=x;i++){
ans=(ans*i)%mod;
}
return ans;
}
void init(){
f[0]=1;
inv[0]=1;
for(int i=1;i<=n;i++){
f[i]=f[i-1]*i%mod;
inv[i]=mgml(f[i],mod-2);
}
}
int cc(int x,int y){
return f[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
scanf("%lld%lld",&n,&k);
if(k>=5002){
init();
int sum=0;
for(int i=1;i<=n;i++){
sum=(sum+cc(n,i)*mgml(i,k)%mod)%mod;
}
printf("%lld",sum);
return 0;
}
s2[0][0]=1;
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
s2[i][j]=(s2[i-1][j-1]+j*s2[i-1][j]%mod)%mod;
}
}
int ans=0;
for(int i=1;i<=k;i++){
int sum;
sum=s2[k][i]*c(n,n-i)%mod*mgml(2,n-i)%mod;
ans=(ans+sum)%mod;
}
cout<<ans<<endl;
}
Make Equal#
太出生了,最后交了一个带
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N],n;
int num[80];
struct asd{
int data,id;
}c[N];
int dp[80][N];
bool amp(asd x,asd y){
return x.data>y.data;
}
signed main(){
// freopen("4.in","r",stdin);
scanf("%lld",&n);
int ma=-1;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
for(int j=1;j<=58;j++){
if(a[i]&(1ll<<(j-1))){
num[j]++;
ma=max(ma,j);
}
}
}
memset(dp,0x7f,sizeof(dp));
dp[0][0]=0;
for(int i=0;i<=ma+1;i++){
memset(c,0,sizeof(c));
for(int j=1;j<=n;j++){
c[j].data=(a[j]&((1ll<<(i-1))-1));
c[j].id=j;
}
sort(c+1,c+n+1,amp);
int k=0;
for(int j=0;j<=n;j++){
if(a[c[j].id]&(1ll<<(i-1))) k++;
if(c[j].data==c[j+1].data && j!=n && j!=0) continue;
dp[i+1][k]=min(dp[i+1][k],dp[i][j]+n-num[i]-j+2*k);//全为1
dp[i+1][num[i]+j-k]=min(dp[i+1][num[i]+j-k],dp[i][j]+num[i]+j-2*k);
}
}
cout<<dp[ma+1][0];
}
都看到这了,还不点个赞。
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17575758.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探