2019吉林省赛

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 }
A

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 }
B

另:指路队友博客题解: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 }
D

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 } 
E

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 } 
F

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 } 
G

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 }
H

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 } 
I

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 }
J

 

转载于:https://www.cnblogs.com/changer-qyz/p/11168462.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值