2022.5.29SCUACM暑假集训前欢乐赛
SCUACM暑假集训前欢乐赛 - Virtual Judge (vjudge.net)
A
先离散化
用树状数组去记录被包含的线段即可
还是很经典的题型了
#include<bits/stdc++.h> using namespace std; struct line{ int l,r,id; }w[200003]; int tot=0; int a[400005],c[400005],ans[200003]; int n; int lowbit(int x){return x&(-x);} bool cmp(line a,line b) { if(a.r==b.r)return a.l>b.l; return a.r<b.r; } void add(int x) { while(x<=tot) { c[x]++; x+=lowbit(x); } } int query(int x) { int res=0; while(x) { res+=c[x]; x-=lowbit(x); } return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { w[i].id=i; scanf("%d%d",&w[i].l,&w[i].r); a[++tot]=w[i].l; a[++tot]=w[i].r; } sort(a+1,a+1+tot); sort(w+1,w+1+n,cmp); tot=unique(a+1,a+tot+1)-(a+1); for(int i=1;i<=n;++i) { int tx=lower_bound(a+1,a+1+tot,w[i].l)-a; int ty=lower_bound(a+1,a+1+tot,w[i].r)-a; //printf("???%d %d\n",query(tx-1),query(ty)); ans[w[i].id]=query(ty)-query(tx-1); add(tx); } for(int i=1;i<=n;++i)printf("%d\n",ans[i]); }
B
求方案数,考虑dp
dp[i]=dp[i-1]+dp[i-k]
#include<bits/stdc++.h> #define LL long long #define P 1000000007 using namespace std; LL dp[100003],sum[100003]; int main() { int T,k;scanf("%d%d",&T,&k); for(int i=0;i<k;++i)dp[i]=1; for(int i=k;i<=100002;++i) { dp[i]=dp[i-1]+dp[i-k]; dp[i]%=P; } for(int i=1;i<=100002;++i) { sum[i]=sum[i-1]+dp[i]; sum[i]%=P; } while(T--) { int a,b;scanf("%d%d",&a,&b); LL ans=sum[b]-sum[a-1]; ans+=P;ans%=P; printf("%lld\n",ans); } }
C
C题当时做的时候题意理解错了卡了好久(脑袋抽抽)
先计算出w*a去判断能不能换,而不是看a是否为b的倍数
#include<bits/stdc++.h> #define LL long long using namespace std; LL gcd(int x,int y) { if (y==0)return x; return gcd(y,x%y); } int main() { int n; double a,b;scanf("%d%lf%lf",&n,&a,&b); for(int i=1;i<=n;++i) { double x;scanf("%lf",&x); LL num=x*a/b; double num2=num*b/a; LL num3=num*(LL)b/(LL)a; if((double)num3<num2)num3++; printf("%lld ",(LL)x-num3); } }
D
判断bfs顺序是否合法,模拟判断
每次vector排序,有矛盾就输出No
#include<bits/stdc++.h> #define LL long long using namespace std; vector<int>q,son; vector<int>d[200005]; int a[200005],ord[200005]; int vis[200005]; int n; bool cmp(int a,int b) { return ord[a]<ord[b]; } void bfs(int x) { memset(vis,0,sizeof(vis)); q.push_back(0);//下标问题 q.push_back(x); vis[x]=1; for(int i=1;i<=n;++i) { if(a[i]!=q[i]) { printf("No\n"); return; } int u=a[i]; son.clear(); for(int j=0;j<d[u].size();++j) { int v=d[u][j]; if(vis[v])continue; son.push_back(v); vis[v]=1; } sort(son.begin(),son.end(),cmp); for(int j=0;j<son.size();++j) q.push_back(son[j]); } printf("Yes\n"); } int main() { scanf("%d",&n); for(int i=1;i<n;++i) { int a,b;scanf("%d%d",&a,&b); d[a].push_back(b); d[b].push_back(a); } for(int i=1;i<=n;++i) { scanf("%d",&a[i]); ord[a[i]]=i; } bfs(1); }
E
简单等比数列问题
#include<bits/stdc++.h> #define LL long long using namespace std; int main() { double a,b,c,d;scanf("%lf%lf%lf%lf",&a,&b,&c,&d); double p1=a/b,p2=c/d; double q=(1-p1)*(1-p2); double w=1; for(int i=1;i<=100000;++i) w*=q; printf("%.8lf",p1*(1-w)/(1-q)); }
F
树上相邻的三个点颜色要不同,子树中儿子的颜色也不能相同
在dfs的时候判断
#include<bits/stdc++.h> #define LL long long using namespace std; struct EDGE{ int to,nextt; }w[400003]; int n; int tot=0; int head[200003],color[200003]; void add(int a,int b) { tot++; w[tot].nextt=head[a]; w[tot].to=b; head[a]=tot; } void dfs(int x,int fa) { int num=1; for(int i=head[x];i;i=w[i].nextt) { int v=w[i].to; if(v==fa)continue; while(num==color[x]||num==color[fa])num++; color[v]=num++; dfs(v,x); } } int main() { scanf("%d",&n); for(int i=1;i<n;++i) { int x,y;scanf("%d%d",&x,&y); add(x,y);add(y,x); } color[1]=1; dfs(1,0); int ans=0; for(int i=1;i<=n;++i)ans=max(ans,color[i]); printf("%d\n",ans); for(int i=1;i<=n;++i)printf("%d ",color[i]); }
G
其实是思维题,发现可以转置的话其实就是对角线上的元素变动
对每条对角线上元素进行判断
#include<bits/stdc++.h> #define LL long long using namespace std; int a[1003][1003],b[1003][1003]; int main() { int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&a[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&b[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) for(int k=1;k<=i+j+1;++k) if(a[k][i+j-k]==b[i][j]) { a[k][i+j-k]=0; break; } int flagg=0; for(int i=1;i<=n;++i) { if(flagg)break; for(int j=1;j<=m;++j) if(a[i][j]!=0){flagg=1;break;} } if(flagg)printf("NO"); else printf("YES"); }
H
炮兵阵地,状压dp
枚举时考虑三排的状态
而且先把每种状态放的士兵预处理出来
#include <cstdio> #include <cstring> #define max(a,b) a>b?a:b #define N 11 using namespace std; int di[103],dp[103][1<<N][1<<N],soldier[103],state[1<<N]; bool check1(int a,int b) { if(a&b) return true; return false; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { char s[15]; scanf("%s",s); for(int j=0;j<m;j++) { if(s[j]=='P') di[i]=di[i]<<1; else di[i]=(di[i]<<1)+1; } } int num=0; for(int i=0;i<(1<<m);i++)//最好是预处理出状态,而不是像牛吃草在dp过程中找状态,毕竟要统计不同状态的士兵数 { if(check1(i,i<<1)||check1(i,i<<2)) continue; int k=i; while(k) { soldier[num]+=k&1; k=k>>1; } state[num++]=i; } /***************************************/ // for(int i=0; i<num; i++) printf("%d %d\n",state[i],soldier[i]); /***************************************/ //dp[r][i][j]第r行为i状态,r-1行为j状态 for(int i=0;i<num;i++) { if(check1(state[i],di[1])) continue; dp[1][i][0]=soldier[i]; } for(int i=0;i<num;i++) { if(check1(state[i],di[2])) continue; for(int j=0;j<num;j++) { if(check1(state[j],di[1])) continue; if(check1(state[i],state[j])) continue; dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+soldier[i]); } } for(int r=3;r<=n;r++) { for(int i=0;i<num;i++) { if(check1(state[i],di[r])) continue; for(int j=0;j<num;j++) { if(check1(state[j],di[r-1])) continue; if(check1(state[i],state[j])) continue; for(int k=0;k<num;k++) { if(check1(state[k],di[r-2])) continue; if(check1(state[k],state[i])||check1(state[j],state[k])) continue; dp[r][i][j]=max(dp[r-1][j][k]+soldier[i],dp[r][i][j]); } } } } int ans=0; for(int i=0;i<num;i++) for(int j=0;j<num;j++) ans=max(ans,dp[n][i][j]); printf("%d",ans); }