2018.08.16

遗憾啊,三道题都不难,但是一道也没AC。

T1 mine

可以看出是个DP题(然而我考场上写的并不是DP,而且它对拍没错),

设:

f[i][j][0/1]代表已经处理完前i个数,且第i个数取j的方案数(0/1代表j==1时地雷在左/右,其他情况无用)

(j:3为是炸弹,0,1,2对应题目中的0,1,2)

于是便有:

f[i][0][0]=f[i-1][0][0]+f[i-1][1][0];(a[i]=='0'/'?')

f[i][1][0]=f[i-1][3][0];(a[i]=='1'/'?')

f[i][1][1]=f[i-1][0][0]+f[i-1][1][0];(a[i]=='1'/'?')

f[i][2][0]=f[i-1][3][0];(a[i]=='2'/'?')

f[i][3][0]=f[i-1][3][0]+f[i-1][1][1]+f[i-1][2][0];(a[i]=='3'/'?')(注意这里可以由上次的3转移)

设初值需要分类讨论,不再赘述。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define AA puts("ALITA")
 4 #define DD puts("DYBALA")
 5 using namespace std;
 6 const int N=1e6+10,mod=1e9+7;
 7 int ans,n,f[N][4][2];
 8 char s[N];
 9 signed main()
10 {
11         //freopen("1.in","r",stdin);
12         //freopen("1.out","w",stdout);
13         scanf("%s",s+1);
14         n=strlen(s+1);
15         if(s[1]=='0'||s[1]=='?') f[1][0][0]=1;
16         if(s[1]=='1'||s[1]=='?') f[1][1][1]=1;
17         if(s[1]=='*'||s[1]=='?') f[1][3][0]=1;
18         for(int i=2;i<=n;i++)
19         {
20                 if(s[i]=='0'||s[i]=='?') f[i][0][0]=(f[i-1][1][0]+f[i-1][0][0])%mod;
21                 if(s[i]=='1'||s[i]=='?')
22                 {
23                         f[i][1][0]=f[i-1][3][0];
24                         f[i][1][1]=(f[i-1][0][0]+f[i-1][1][0])%mod;
25                 }
26                 if(s[i]=='2'||s[i]=='?') f[i][2][0]=f[i-1][3][0];
27                 if(s[i]=='*'||s[i]=='?') f[i][3][0]=(f[i-1][1][1]+f[i-1][2][0]+f[i-1][3][0])%mod;
28         }
29         if(s[n]=='0'||s[n]=='?') (ans+=f[n][0][0])%=mod;
30         if(s[n]=='1'||s[n]=='?') (ans+=f[n][1][0])%=mod;
31         if(s[n]=='*'||s[n]=='?') (ans+=f[n][3][0])%=mod;
32         printf("%lld",ans);
33         return 0;
34 }
T1

T2 water

0~?分:

对于每个点枚举能到达的高度,bfs检查是否合法,时间复杂度$ O(n^2m^2*1e9) $

60分做法:

把枚举变为二分,复杂度大大降低,$ O(n^2m^2log2(1e9)) $,性价比较高

100分做法:

我们观察水流出的过程,可以看出一个块的ans一定为它走到矩阵外路径的最大值的最小值,

因为要想出去,一定是路径上最大值,而它可以从四面八方出去,所以在所以的路径的最大值中取min。

之后考虑如何建图,两个块之间的路的权值就是两个块的高度的最大值,源点的高度就是0。

1>求单源最短路,DJ即可(网格图Spfa可能会死)

2>最小生成树,f[i]即为i到源点(根)的路径的权值最大值。

  1 #include<bits/stdc++.h>
  2 #define int long long
  3 #define max(a,b) (a>b?a:b)
  4 #define AA puts("ALITA")
  5 #define DD puts("DYBALA")
  6 using namespace std;
  7 const int N=305;
  8 int sum,tot,cnt,T,n,m,a[N][N],ma[N][N],fa[N*N],head[N*N],to[N*N*2],ne[N*N*2],w[N*N*2],dis[N*N];
  9 int A[2]={0,-1};
 10 int B[2]={-1,0};
 11 struct edge{int fr,to,w;}e[N*N*4];
 12 int read()
 13 {
 14         register int sum,k=1;register char s;
 15         while(s=getchar(),s<'0'||s>'9') if(s=='-') k=-1;sum=s-'0';
 16         while(s=getchar(),s>='0'&&s<='9') sum=sum*10+s-'0';
 17         return k*sum;
 18 }
 19 void add(int x,int y,int z)
 20 {
 21         e[++cnt].fr=x;
 22         e[cnt].to=y;
 23         e[cnt].w=z;
 24 }
 25 void connect(int x,int y,int z)
 26 {
 27         to[++sum]=y;
 28         w[sum]=z;
 29         ne[sum]=head[x];
 30         head[x]=sum;
 31 }
 32 bool comp(edge l,edge r)
 33 {
 34         return l.w<r.w;
 35 }
 36 int get(int x)
 37 {
 38         if(fa[x]==x) return x;
 39         return fa[x]=get(fa[x]);
 40 }
 41 void dfs(int x,int father)
 42 {
 43         for(int i=head[x];i;i=ne[i])
 44         {
 45                 int y=to[i];
 46                 if(y==father) continue;
 47                 dis[y]=max(dis[x],w[i]);
 48                 dfs(y,x);
 49         }
 50 }
 51 signed main()
 52 {
 53         //freopen("1.in","r",stdin);
 54         n=read();m=read();
 55         T=n*m+1;
 56         for(int i=1;i<=n;i++)
 57         {
 58                 for(int j=1;j<=m;j++)
 59                 {
 60                         ma[i][j]=++tot;
 61                         a[i][j]=read();
 62                 }
 63         }
 64         for(int i=1;i<=n;i++)
 65         {
 66                 for(int j=1;j<=m;j++)
 67                 {
 68                         for(int k=0;k<2;k++)
 69                         {
 70                                 int l=i+A[k],r=j+B[k];
 71                                 if(!ma[l][r]) continue;
 72                                 add(ma[i][j],ma[l][r],max(a[i][j],a[l][r]));
 73                         }
 74                 }
 75         }
 76         for(int i=1;i<=n;i++)
 77         {
 78                 add(ma[i][1],T,max(a[i][1],0));
 79                 add(ma[i][m],T,max(a[i][m],0));
 80         }
 81         for(int i=2;i<m;i++)
 82         {
 83                 add(ma[1][i],T,max(a[1][i],0));
 84                 add(ma[n][i],T,max(a[n][i],0));
 85         }
 86         for(int i=1;i<=tot+1;i++) fa[i]=i;
 87         sort(e+1,e+cnt+1,comp);
 88         for(int i=1,x,y;i<=cnt;i++)
 89         {
 90                 x=get(e[i].fr),y=get(e[i].to);
 91                 if(x==y) continue;
 92                 fa[x]=y;
 93                 connect(e[i].fr,e[i].to,e[i].w);
 94                 connect(e[i].to,e[i].fr,e[i].w);
 95         }
 96         dfs(T,0);
 97         for(int i=1;i<=n;i++)
 98         {
 99                 for(int j=1;j<=m;j++)
100                 {
101                         printf("%lld ",dis[ma[i][j]]-a[i][j]);
102                 }
103                 puts("");
104         }
105         return 0;
106 }
T2

T3 gcd

考场上想到了正解,但当时一时脑抽觉得一个500000的数的质因子可能有好多好多个...(大雾)

20分做法:

暴力搞它~,时间复杂度$ O(nm*2log2(max(a,b)) $

50分做法:

30分部分分满足max(a[i])<=100,于是可以用一个桶来存储,更新答案,复杂度$ O(m*100)

(注意gcd要预处理,否则像我这样自带大常数的根本过不去!!!)

100分做法:

跟题解不太一样,但又有异曲同工之妙。

设sum1为原来被激活的数的个数,sum2为其中与a[i]组成不合法的数的个数

显然nowans=lastans+sum1-sum2;sum1好求,关键在于sum2。

仍然是用桶v[x]代表x|a[i]的个数,我们可以容斥来解决,

具体来说就是:枚举每个素因子是否取,在$ O(2^6) $内求出没种情况,容斥即可。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define max(a,b) (a>b?a:b)
 4 #define AA puts("ALITA")
 5 #define DD puts("DYBALA")
 6 using namespace std;
 7 const int N=2e5+10;
 8 int sum,ans,n,m,tot[N],mark[N],a[N],p[N][8],v[N*3];
 9 int read()
10 {
11         register int sum,k=1;register char s;
12         while(s=getchar(),s<'0'||s>'9') if(s=='-') k=-1;sum=s-'0';
13         while(s=getchar(),s>='0'&&s<='9') sum=sum*10+s-'0';
14         return k*sum;
15 }
16 void init(int x,int y)
17 {
18         for(int i=2;i<=sqrt(x);i++)
19         {
20                 if(x%i) continue;
21                 p[y][++tot[y]]=i;
22                 while(x%i==0) x/=i;
23         }
24         if(x!=1) p[y][++tot[y]]=x;
25 }
26 void dfs(int x,int y,int z,int val)
27 {
28         if(y==tot[x]+1)
29         {
30                 if(val==1) return;
31                 ans+=v[val]*z;
32                 return;
33         }
34         dfs(x,y+1,z*(-1),val*p[x][y]);
35         dfs(x,y+1,z,val);
36 }
37 void redfs(int x,int y,int z,int val)
38 {
39         if(y==tot[x]+1) 
40         {
41                 v[val]+=z;
42                 return;
43         }
44         redfs(x,y+1,z,val*p[x][y]);
45         redfs(x,y+1,z,val);
46 }
47 signed main()
48 {
49         //freopen("1.in","r",stdin);
50         n=read();m=read();
51         for(int i=1;i<=n;i++) 
52         {
53                 a[i]=read();
54                 init(a[i],i);
55         }
56         for(int i=1,x;i<=m;i++)
57         {
58                 x=read();
59                 mark[x]^=1;
60                 if(mark[x])
61                 {
62                         ans+=sum;
63                         sum++;
64                         dfs(x,1,1,1);
65                         redfs(x,1,1,1);
66                 }
67                 else 
68                 {
69                         sum--;
70                         ans-=sum;
71                         redfs(x,1,-1,1);
72                         dfs(x,1,-1,1);
73                 }
74                 printf("%lld\n",ans);
75         }
76         return 0;
77 }
T3

猜你喜欢

转载自www.cnblogs.com/AthosD/p/11365289.html
今日推荐