csps模拟83最大异或和简单的括号序列旅行计划题解

题面:https://www.cnblogs.com/Juve/articles/11733280.html

最大异或和:

简单博弈,小Q一定不会输,如果异或和为0,则平局,因为无论小Q如何拿,小T都会拿到和小Q一样

如果异或和不为0,则小Q只要取走二进制下最高位的那个数即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 const int MAXN=1e5+5;
 8 int t,n,w[MAXN],tot=0;
 9 signed main(){
10     scanf("%lld",&t);
11     while(t--){
12         tot=0;
13         scanf("%lld",&n);
14         for(int i=1;i<=n;++i) scanf("%lld",&w[i]),tot^=w[i];
15         for(int i=1,u,v;i<n;++i) scanf("%lld%lld",&u,&v);
16         if(tot!=0) puts("Q");
17         else puts("D");
18     }
19     return 0;
20 }
View Code

简单的括号序列:

组合数学,记住不要重复

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 #define re register
 7 using namespace std;
 8 const int MAXN=200005,mod=1e9+7;
 9 int len,ans=0,f[MAXN],g[MAXN];
10 char s[MAXN];
11 int fac[MAXN],inv[MAXN];
12 int q_pow(int a,int b,int p){
13     int res=1;
14     while(b){
15         if(b&1) res=res*a%p;
16         a=a*a%p;
17         b>>=1;
18     }
19     return res;
20 }
21 void get_c(int N){
22     fac[0]=fac[1]=inv[0]=1;
23     for(int i=2;i<=N;++i) fac[i]=fac[i-1]*i%mod;
24     inv[N]=q_pow(fac[N],mod-2,mod);
25     for(int i=N-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
26 }
27 int C(int n,int m){
28     if(m>n) return 0;
29     if(m==n) return 1;
30     return fac[n]*inv[m]%mod*inv[n-m]%mod;
31 }
32 signed main(){
33     scanf("%s",s+1);
34     len=strlen(s+1);
35     get_c(len+2);
36     for(re int i=1;i<=len;++i){
37         f[i]=f[i-1];
38         if(s[i]=='(') ++f[i];
39     }
40     for(re int i=len;i>0;--i){
41         g[i]=g[i+1];
42         if(s[i]==')') ++g[i];
43     }
44     for(int i=1;i<=len;++i){
45         if(s[i]=='(') ans=(ans+C(f[i]+g[i]-1,g[i]-1))%mod;
46     }
47     printf("%lld\n",ans);
48     return 0;
49 }
View Code

旅行计划:

floyed终于用上了。。。

设f[i][j][k]表示从i到j走k步的最短距离,这很好转移

然后设g[i][j][k]表示从i到j走k×100步的最短距离,用f数组转移

然后把f数组按照k从大到小更新,把f数组转化为i到j走至少k步的最短距离

然后询问时的答案就是min(g[s][i][k/100]+f[i][t][k%100]),$i\in[1,n]$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define re register
 6 using namespace std;
 7 const int inf=0x3f3f3f3f;
 8 int n,m,mp[55][55],q,ans,s,t,k,f[55][55][115],g[55][55][115];
 9 void floyed(){
10     for(int i=1;i<=n;++i) f[i][i][0]=g[i][i][0]=0;
11     for(int k=1;k<=110;++k){
12         for(int i=1;i<=n;++i)
13             for(int j=1;j<=n;++j)
14                 for(int p=1;p<=n;++p)
15                     f[i][j][k]=min(f[i][j][k],f[i][p][k-1]+mp[p][j]);
16     }
17     for(int k=1;k<=100;++k){
18         for(int i=1;i<=n;++i)
19             for(int j=1;j<=n;++j)
20                 for(int p=1;p<=n;++p)
21                     g[i][j][k]=min(g[i][j][k],g[i][p][k-1]+f[p][j][100]);
22     }
23     for(int i=1;i<=n;++i){
24         for(int j=1;j<=n;++j)
25             for(int k=110;k>=0;--k)
26                 f[i][j][k]=min(f[i][j][k+1],f[i][j][k]);
27     }
28 }
29 signed main(){
30     scanf("%d%d",&n,&m);
31     memset(mp,0x3f,sizeof(mp));
32     memset(f,0x3f,sizeof(f));
33     memset(g,0x3f,sizeof(g));
34     for(re int i=1,u,v,w;i<=m;++i){
35         scanf("%d%d%d",&u,&v,&w);
36         mp[u][v]=min(mp[u][v],w);
37     }
38     floyed();
39     scanf("%d",&q);
40     while(q--){
41         ans=inf;
42         scanf("%d%d%d",&s,&t,&k);
43         for(int i=1;i<=n;++i)
44             ans=min(ans,g[s][i][k/100]+f[i][t][k%100]);
45         if(ans>=inf) ans=-1;
46         printf("%d\n",ans);
47     }
48     return 0;
49 }
View Code

 

posted @ 2019-10-24 17:09  xukl21  阅读(164)  评论(0编辑  收藏  举报