牛客练习赛43
A题:Tachibana Kanade Loves School
水题,看清"YE5"和"N0"而不是"YES"、"NO";
#include<bits/stdc++.h> using namespace std; int main(){ int n,a[110],b[110]; cin>>n; for(int i=0;i<n;i++){ cin>>a[i]>>b[i]; } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(i==j) continue; if(a[i]+b[i]==a[j]&&a[j]+b[j]==a[i]){ cout<<"YE5"<<endl; return 0; } } } cout<<"N0"<<endl; return 0; }
B题:Tachibana Kanade Loves Probability
快速幂取模+快速除
#include<bits/stdc++.h> using namespace std; long long m,n,k1,k2; long long powerMod(int a,long long b){ long long ans=m; a=a%n; while(b>0){ if(b&1) ans=(long long)ans*a%n; a=(long long)a*a%n; b/=2; } return ans; } int main(){ std::ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>m>>n>>k1>>k2; long long p,q; p=powerMod(10,k1-1); for(int i=k1;i<=k2;i++) { cout<<p*10/n; p=p*10%n; } cout<<endl; } }
C题:Tachibana Kanade Loves Review
最小生成树
题目求能不能在t天内学完所有知识点,将每个知识点看成一个顶点,知识点间的联系看成边,这样问题就简化成了一个求最小生成树的问题了。但是还有一些点之间是没有联系的,即图是不连通的,所以我们需要引入一个节点0,将(0,i)这条边的权值定为Ti,这样图就联通了。另外就是条件k了,k个已经学习的知识点表明(0,ki)这条路径已经加入到最小生成树中,只需用并查集合并就好。
#include<bits/stdc++.h> using namespace std; const int N=1e6 + 10; const int M=7e6 + 10;//一共有m+n条边 不知道为什么6e6+10 就会超时 int n,m,k; long long t,sum=0; int T; struct Edge { int form,to,w; bool operator < (const Edge x)const{ return w<x.w; } }e[M]; int cnt=0; void addEdge(int u,int v,int w){ e[++cnt].to=v; e[cnt].w=w; e[cnt].form=u; } int f[N]; int find(int x){ return f[x]==x? x: f[x]=find(f[x]); } inline int read(){//快读 long long x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*f; } int main(){ n=read();m=read();k=read();t=read(); //printf("%d %d %d %lld ",n,m,k,t); f[0]=0; for(int i=1;i<=n;i++){ f[i]=i; T=read(); addEdge(0,i,T);//每个节点和虚拟节点0创建边 边权为点代价 } int tmp; for(int i=1;i<=k;i++) { tmp=read(); //printf("%d ",tmp); f[tmp]=0;//已有节点和虚拟节点0连接 } int x,y,h; for(int i=0;i<m;i++){ x=read();y=read();h=read(); //printf("%d %d %d ",x,y,h); addEdge(x,y,h); } sort(e+1,e+cnt+1); int ans=k; for(int i=1;i<=cnt;i++){ x=find(e[i].form),y=find(e[i].to),h=e[i].w; if(x!=y){ f[x]=y; sum+=h; ans++; } else continue; if(ans==n-1||sum>t) break; } //cout<<sum; if(sum>t)printf("No "); else printf("Yes "); return 0; }
F题:Tachibana Kanade Loves Game
当k+(n- n中是2~m倍数的个数)<q 输出QAQ
所以只要找到n中是2~m倍数的个数题目就可以解决。
2<=m<=20 但是可以排除一些数,比如6,如果x是2的倍数,那么x肯定是6的倍数,所以找到n中是m中素数的倍数个数就行,m的取值为a[]={2,3,5,7,11,13,17,19}。
然后用容斥原理解题。
kjj,今天数学老师讲了欧拉函数才懂这题;这题和用容斥原理证明欧拉函数的过程差不多。
n中a[i]倍数的个数为n/a[i] ,
n-n中是2~m倍数的个数=n-(n/a[0]+n/a[1]+...+n/a[7])+ (n/(a[0]*a[1]+...+n/(a[7]*a[8])) - ...+(-1)7*n/(a[0]*...*a[n])=n*(1-1/a[0])*....*(1-1/a[7])
欧拉函数推理:
#include <bits/stdc++.h> #define ll long long using namespace std; int a[]={2,3,5,7,11,13,17,19}; int main() { int t; scanf("%d", &t); ll k, q, n, m; while (t--) { scanf("%lld%lld%lld%lld", &k, &q, &n, &m); if (k==0) printf("QAQ "); else { ll ans = n; int cnt=8; for (int i=0; i<8 ; i++) if(m<a[i]){ cnt=i;break; } for (int i=0; i<cnt ; i++) ans=ans*(a[i]-1)/a[i]; if ( k+ans>q ) printf("Yes "); else printf("QAQ "); } } }