A.
题意:已知$a,b,c,k$,每次操作为:
1.If a>b then a = a - b.
2.If b>c then b = b - c.
3.If c>a then c = c - a.
操作k次后,询问最终的$a,b,c$为多少?
分析:暴力模拟即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 int t;scanf("%d",&t); 5 int x,y,z,k; 6 while (t--){ 7 scanf("%d%d%d%d",&x,&y,&z,&k); 8 while (k>0){ 9 if(x==y && y==z) break; 10 if (x>y) x-=y; 11 if (y>z) y-=z; 12 if (z>x) z-=x; 13 k--; 14 } 15 printf("%d %d %d\n",x,y,z); 16 } 17 return 0; 18 }
B.
题意:已知一棵n个结点的树,首先有以下两个定义:
礼物边:不存在相邻边与他颜色相同。
礼物点:在某一棵树内,从x点开始的路径均为礼物边。
每次询问x,即以x为根的子树内礼物节点的个数为多少。
分析:
比赛的时候题意一直读不通(事实上是,赛场后题意也读不懂。至今和队友还是有题意纠结???但是两份代码都过了??数据是真的水。
考虑每次询问x时,有这样两种情况是不满足定义的:
1. 父亲到x与x到儿子的颜色相同。这种情况下,对于以父亲为根的子树内,父亲本身是不满足题意要求的。
2. 点x存在去往两个儿子的边颜色相同。这种情况下,我们不再需要考虑对于这两个儿子子树对于答案的贡献,可以直接无视这两个儿子子树了。
代码:(来自xjb大佬,我写了一份假代码。我hacak我自己.jpg
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define N 200005 4 #define P pair<int,int> 5 using namespace std; 6 int n,l,r,c,x,f[N]; 7 vector<P>G[N]; 8 int dfs(int x,int fa,int lstc){ 9 f[x]=1; 10 int num=0,num1=0; 11 map<int,int>mp; 12 for(auto u:G[x]) 13 if(u.first!=fa){ 14 int tmp=dfs(u.first,x,u.second); 15 if(mp.find(u.second)!=mp.end()) mp[u.second]=0;else mp[u.second]=tmp; 16 if(u.second==lstc) f[fa]=0; 17 } 18 for(auto u:mp){ 19 num+=u.second; 20 if(u.first!=lstc) num1+=u.second; 21 } 22 num1+=f[x]; 23 f[x]+=num; 24 return num1; 25 } 26 int main(){ 27 scanf("%d",&n); 28 for(int i=1;i<n;i++){ 29 scanf("%d%d%d",&l,&r,&c); 30 G[l].push_back(P(r,c)); 31 G[r].push_back(P(l,c)); 32 } 33 dfs(1,-1,-1); 34 int Q; 35 scanf("%d",&Q); 36 while(Q--){ 37 scanf("%d",&x); 38 printf("%d\n",f[x]); 39 } 40 }
另:指路队友博客题解:dfs序+差分。https://blog.csdn.net/qq_43813163/article/details/95348450
D.
题意:已知一棵n个节点的树,对于任一一个点集S,询问答案$\sum_{s\subset S}f(s)$。其中对于$f(s)$的定义为:$f(s)=a[LCA(S)] (s 非空)$。
分析:题意可以变为对于每一个结点x,他对于整个题答案的贡献为多少,即他出现在了多少个集合之中。考虑每一个点的时候,考虑x作为一个集合S的LCA出现的次数即可。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 const ll mod=1e9+7; 6 vector<int> mp[maxn]; 7 int sz[maxn],a[maxn]; 8 ll ans; 9 ll pow_(int x,int y){ 10 ll res=1ll,base=1ll*x; 11 while (y){ 12 if (y&1) (res*=base)%=mod; 13 (base*=base)%=mod; 14 y>>=1; 15 } 16 return res; 17 } 18 void dfs(int x,int fa){ 19 ll num=0; 20 for (int i=0;i<mp[x].size();i++){ 21 if (mp[x][i]==fa) continue; 22 dfs(mp[x][i],x); 23 sz[x]+=sz[mp[x][i]]; 24 ll kk=pow_(2,sz[mp[x][i]]); 25 (num+=kk-1+mod)%=mod; 26 } 27 sz[x]++; 28 ll tmp=(pow_(2,sz[x])-1-num+mod)%mod; 29 (ans+=(1ll*a[x]*tmp))%=mod; 30 } 31 32 int main(){ 33 int n,x,y; 34 scanf("%d",&n); 35 for (int i=1;i<=n;i++) scanf("%d",&a[i]),sz[i]=0; 36 for (int i=0;i<n-1;i++){ 37 scanf("%d%d",&x,&y); 38 mp[x].push_back(y); 39 mp[y].push_back(x); 40 } 41 mp[1].push_back(0); 42 ans=0; 43 dfs(1,0); 44 printf("%lld\n",ans); 45 return 0; 46 }
E.
题意:用火柴棒拼接小正方形,问拼成n个小正方形所需要的最少木棍数为多少?
分析:找规律题。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll solve(ll n){ 5 ll tmp=sqrt(n); 6 if (tmp*tmp==n) return (n+tmp)*2; 7 ll m=(tmp+1)*(tmp+1); 8 ll len=m-tmp*tmp-1; 9 ll res=0; 10 if (tmp*tmp+len/2>=n){ 11 res+=2*(tmp+tmp*tmp); 12 res+=(n-tmp*tmp)*2+1; 13 } 14 else{ 15 res+=2*(tmp+tmp*tmp); 16 res+=(n-tmp*tmp)*2+2; 17 } 18 return res; 19 } 20 int main(){ 21 int t; scanf("%d",&t); 22 ll n; 23 while (t--){ 24 scanf("%lld",&n); 25 ll ans=solve(n); 26 printf("%lld\n",ans); 27 } 28 return 0; 29 }
F.
题意:已知一张图$dis[n][n]$,其中$dis[i][j]$代表两点之间的“最短路”。重新构建一张新图,问最少保留几条边可以满足两点之间路径最短。
分析:floyd过程中不断去松弛两点间的最短路,如果可松弛,那么原来存的边就可以不保留。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=310; 4 const int inf=0xfffffff; 5 int a[maxn][maxn],vis[maxn][maxn]; 6 int main(){ 7 int n;scanf("%d",&n); 8 for (int i=1;i<=n;i++) 9 for (int j=1;j<=n;j++){ 10 scanf("%d",&a[i][j]); 11 vis[i][j]=1; 12 } 13 int ans=0; 14 for (int i=1;i<=n;i++){ 15 for (int j=1;j<=n;j++){ 16 if (i==j) continue; 17 for (int k=1;k<=n;k++){ 18 if (j==k || i==k) continue; 19 if (a[i][k]+a[k][j]<=a[i][j]){ 20 vis[i][j]=0;vis[j][i]=0; 21 a[i][j]=a[i][k]+a[k][j]; 22 } 23 } 24 } 25 } 26 for (int i=1;i<=n;i++) 27 for (int j=1;j<=n;j++) if (!vis[i][j]) ans++; 28 printf("%d\n",(n*n-ans-n)/2); 29 return 0; 30 }
G.
题意:已知两点$s,e$,有一束光线从s开始指向e,询问是否点$(px,py)$在这束光线上。
分析:判断点在射线上。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const double eps=1e-10; 4 int sgn(double x){ 5 if (fabs(x)<eps) return 0; 6 if (x<0) return -1; 7 return 1; 8 } 9 int main(){ 10 int t; scanf("%d",&t); 11 double sx,sy,ex,ey,px,py; 12 while (t--){ 13 scanf("%lf%lf%lf%lf",&sx,&sy,&ex,&ey); 14 scanf("%lf%lf",&px,&py); 15 if (sgn(ex-sx)==sgn(sx-px) && sgn(ey-sy)==sgn(sy-py)){ 16 printf("NO\n"); 17 continue; 18 } 19 if (sx==ex){ 20 if (px==sx) printf("YES\n"); 21 else printf("NO\n"); 22 continue; 23 } 24 if (sy==ey){ 25 if (py==sy) printf("YES\n"); 26 else printf("NO\n"); 27 continue; 28 } 29 double k=(sy-ey)/(sx-ex); 30 double b=sy-k*sx; 31 double tmp=k*px+b; 32 if (sgn(tmp-py)==0) printf("YES\n"); 33 else printf("NO\n"); 34 } 35 return 0; 36 }
H.
题意:有n个“up",m个"down",构造一个序列,要求每一点处的"up"数量$\geq$"down"数量。同时,还需要挑选k个时间添加背景音乐。询问总的方案数为多少?答案需要%(1e5+3)。
分析:卡特兰数应用。(我也不知道怎么推。但这个题和hdoj1133基本一样。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int mod=1e5+3; 4 const int N=1e5+3; 5 typedef long long ll; 6 ll fac[N],inv_fac[N]; 7 ll qpow(ll a,ll b){ 8 ll ret=1,tmp=a; 9 while(b){ 10 if(b&1) (ret*=tmp)%=mod; 11 b/=2; 12 (tmp*=tmp)%=mod; 13 } 14 return ret; 15 } 16 void init(){ 17 fac[0]=1; 18 for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod; 19 inv_fac[N-1]=qpow(fac[N-1],mod-2); 20 for(int i=N-2;i>=0;i--) inv_fac[i]=inv_fac[i+1]*(i+1)%mod; 21 } 22 ll C(int n,int m){ 23 return (fac[n]*inv_fac[n-m]%mod)*inv_fac[m]%mod; 24 } 25 ll Lucas(int n,int m) 26 { 27 if(m>n) return 0; 28 ll ret=1; 29 while(m>0LL){ 30 ret=(ret*C(n%mod,m%mod))%mod; 31 m/=mod; 32 n/=mod; 33 } 34 return ret; 35 } 36 int main(){ 37 init(); 38 int n,m,k;scanf("%d%d%d",&n,&m,&k); 39 int ans=Lucas(n+m,n)-Lucas(n+m,n+1); 40 ans=1ll*ans*Lucas(n+m,k)%mod; 41 printf("%d\n",ans); 42 return 0; 43 }
I.
题意:convert all “ig”, “IG” and “Ig” including in the string to “iG”.
分析:模拟。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 string s; 5 cin >> s; 6 int len=s.size(); 7 for (int i=0;i<len-1;i++){ 8 if ((s[i]=='i' || s[i]=='I') && (s[i+1]=='g' || s[i+1]=='G')){ 9 s[i]='i'; s[i+1]='G'; 10 } 11 } 12 cout << s << endl; 13 return 0; 14 }
J.
题意:求公式:$[cos^2(\frac{(n+1)!+1)}{n}\ast\pi)]$。$2\le n\le 1e9$
分析:打表找规律。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int check(int n){ 5 int kk=sqrt(n); 6 for(int i=2;i<=kk;i++){ 7 if (n%i==0) return false; 8 } 9 return true; 10 } 11 int main(){ 12 int t;scanf("%d",&t); 13 int n; 14 while(t--){ 15 scanf("%d",&n); 16 if (check(n)) printf("1\n"); 17 else printf("0\n"); 18 } 19 return 0; 20 }