A.骰⼦的游戏
水题,直接暴力枚举六个面再比较大小,完结散花。
时间复杂度O(6*6)
#include<bits/stdc++.h> using namespace std; int T,x,y,a[7],b[7]; int main() { scanf("%d",&T); while(T--) { x=0;y=0; for(int i=1;i<=6;i++)scanf("%d",&a[i]); for(int i=1;i<=6;i++)scanf("%d",&b[i]); for(int i=1;i<=6;i++) for(int j=1;j<=6;j++) if(a[i]>b[j])x++; else if(a[i]<b[j])y++; if(x>y)puts("Alice"); if(x<y)puts("Bob"); if(x==y)puts("Tie"); } return 0; }
B.购物
dp题,中等偏下难度(我不知道为什么我的记忆化搜索萎了)
表示前i天,买j个糖果的最小代价。
时间复杂度O(n^3)
#include<bits/stdc++.h> using namespace std; const int N=305; int n,m,sum[N][N],f[N][N]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) scanf("%d",&sum[i][j]); sort(sum[i]+1,sum[i]+m+1); for(int j=2;j<=m;j++) sum[i][j]+=sum[i][j-1]; } memset(f,0x3f,sizeof(f)); f[0][0]=0; for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) for(int k=i-1;k<=j;k++) if(j-k<=m) f[i][j]=min(f[i][j],f[i-1][k]+sum[i][j-k]+(j-k)*(j-k)); cout<<f[n][n]; return 0; }
C.随机树
这题较难,思维上要用唯一分解定理,代码实现上要用树链剖分(或dfs序)。
唯一分解定理:任何一个数都能被分解成若干质数的若干次数的乘积,也就是分解质因数()
因数个数为每一个质数加1的乘积,比如12,因数个数为(2+1)*(1+1))
时间复杂度O(nlog(n))
#include<bits/stdc++.h> using namespace std; #define mid (l+r)/2 #define int long long const int mod=1e9+7; const int xu[6]={2,3,5,7,11,13}; const int N=100005; int n,m,x,y,top,a[N],ans[10],head[N],seg[N],rev[N],size[N]; char s[N]; struct node{ int too,next; }edge[N*2]; struct node2{ int jia[10]; }tree[N*4]; int kuai(int a,int b) { if(b==0)return 1; if(b==1)return a; int x=kuai(a,b/2); if(b%2==0)return x*x%mod; return x*x%mod*a%mod; } void add(int a,int b) { edge[++top].too=b;edge[top].next=head[a];head[a]=top; } void dfs(int u,int fa) { seg[u]=++seg[0]; rev[seg[0]]=u; size[u]=1; for(int i=head[u];i;i=edge[i].next) { int v=edge[i].too; if(v==fa)continue; dfs(v,u); size[u]+=size[v]; } } void pushup(int nod) { for(int i=0;i<6;i++) tree[nod].jia[i]=(tree[nod*2].jia[i]+tree[nod*2+1].jia[i])%mod; } void build(int nod,int l,int r) { if(l==r) { for(int i=0;i<6;i++) { while(a[rev[l]]%xu[i]==0) { tree[nod].jia[i]++; tree[nod].jia[i]%=mod; a[rev[l]]/=xu[i]; } } return; } build(nod*2,l,mid);build(nod*2+1,mid+1,r); pushup(nod); } void change(int nod,int l,int r,int x,int val) { if(l==r) { for(int i=0;i<6;i++) { while(val%xu[i]==0) { tree[nod].jia[i]++; tree[nod].jia[i]%=mod; val/=xu[i]; } } return; } if(x<=mid)change(nod*2,l,mid,x,val); else change(nod*2+1,mid+1,r,x,val); pushup(nod); } void find(int nod,int l,int r,int L,int R) { if(l==L&&r==R) { for(int i=0;i<6;i++)ans[i]=(ans[i]+tree[nod].jia[i])%mod; return; } if(R<=mid)find(nod*2,l,mid,L,R); else if(L>mid)find(nod*2+1,mid+1,r,L,R); else{ find(nod*2,l,mid,L,mid); find(nod*2+1,mid+1,r,mid+1,R); } } signed main() { scanf("%lld",&n); for(int i=1;i<n;i++) { scanf("%lld%lld",&x,&y); x++;y++; add(x,y); add(y,x); } for(int i=1;i<=n;i++)scanf("%lld",&a[i]); dfs(1,0); build(1,1,n); scanf("%lld",&m); while(m--) { scanf("%s",s); if(s[0]=='R') { int res=1,sum=1; scanf("%d",&x); x++; for(int i=0;i<6;i++)ans[i]=0; find(1,1,n,seg[x],seg[x]+size[x]-1); for(int i=0;i<6;i++) { res=(long long)res*kuai(xu[i],ans[i])%mod; sum=(long long)sum*(ans[i]+1)%mod; } printf("%lld %lld\n",res,sum); } else{ scanf("%lld%lld",&x,&y); x++; change(1,1,n,seg[x],y); } } return 0; }
D.珂朵莉的无向图
简单题,直接宽搜。
把一开始的t个点都加入队列,宽搜求出每个点的最短路径。最后记录答案,输出。
时间复杂度O(qn)
#include<bits/stdc++.h> using namespace std; const int N=1e6+5; int n,m,Q,x,y,t,s,top,ans,head[N],dis[N]; queueq; bool vis[N]; struct node{ int too,next; }edge[N]; void add(int a,int b) { edge[++top].too=b;edge[top].next=head[a];head[a]=top; } int main() { scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } while(Q--) { while(!q.empty())q.pop(); scanf("%d%d",&t,&s); ans=0; for(int i=1;i<=n;i++) { vis[i]=false; dis[i]=1e9; } for(int i=1;i<=t;i++) { scanf("%d",&x); q.push(x); dis[x]=0; vis[x]=true; //ans++; } while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i;i=edge[i].next) { int v=edge[i].too; if(!vis[v]) { dis[v]=dis[u]+1; vis[v]=true; q.push(v); //if(dis[v]<=s)ans++; } } } for(int i=1;i<=n;i++) if(dis[i]<=s)ans++; printf("%d\n",ans); } return 0; }
E.珂朵莉的数列
难度中等偏高,思维难度较高,代码实现中等。
我们考虑每个数对答案的贡献,比如总共有8个数,考虑第5个数,如果第3个数和第5个数符合条件,对答案的贡献就是(3-1+1) * (8-5+1)
查找符合条件的数可以用树状数组实现,代码和求逆序对差不多,就是原来是加一,现在是加自己的位置。
注意:要高精度,可以使用两个int,分开来存。
时间复杂度O(nlog(n))
#include<bits/stdc++.h> using namespace std; #define int long long const int N=2000005; int n,ans1,ans2,a[N],b[N],c[N]; int lowbit(int x) { return x&-x; } void add(int x,int y) { while(x<=n) { c[x]+=y; x+=lowbit(x); } } int query(int x) { int res=0; while(x) { res+=c[x]; x-=lowbit(x); } return res; } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b; for(int i=1;i<=n;i++) { int t=(query(n)-query(a[i]))*(n-i+1); add(a[i],i); ans2+=t; ans1+=ans2/10000000000000000ll; ans2%=10000000000000000ll; } if(ans1)printf("%lld%016lld",ans1,ans2); else printf("%lld\n",ans2); return 0; }
全部评论
(1) 回帖