老张说:这套题太简单啦,你们最多两个小时就可以AK啦!
题 1 数数
我看到T1就懵了,这就是老张两个小时可以AK的题的T1??
然后我成功地T1写了1h+,后面1h打了t2.t3暴力,就很开心。
等差数列中的一个数B+A*N,发现A非常小,让人浮想联翩,把这个等差数列中每个数模A,得到的结果就是B%A而且很小,就可以数位dp。f[i][j][0/1]表示长度为i的二进制数,模A等于j,前i位有没有达到上界的方案数,g[i][j][0/1]表示这种情况下的答案。转移什么的看代码吧,就是基础的数位dp。
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 typedef long long LL;
16 typedef double db;
17 using namespace std;
18 int T,A,lim[65],n;
19 LL B,N,f[65][10007][2],g[65][10007][2],pr[65],ans;
20
21 template<typename T>void read(T &x) {
22 char ch=getchar(); x=0; T f=1;
23 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
24 if(ch=='-') f=-1,ch=getchar();
25 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
26 }
27
28 LL find(LL up) {
29 if(!up) return 0;
30 memset(f,0,sizeof(f));
31 memset(g,0,sizeof(g));
32 Rep(i,59,0) if(up&(1LL<<i)) { n=i; break; }
33 For(i,0,n) lim[n-i]=(up&pr[i])?1:0;
34 f[0][0][1]=1;
35 For(i,0,n) {
36 For(j,0,A-1) if(f[i][j][0]||f[i][j][1]) {
37 f[i+1][(j*2+1)%A][0]+=f[i][j][0];
38 g[i+1][(j*2+1)%A][0]+=g[i][j][0]+f[i][j][0];
39 f[i+1][j*2%A][0]+=f[i][j][0];
40 g[i+1][j*2%A][0]+=g[i][j][0];
41 if(lim[i]==0) {
42 f[i+1][j*2%A][1]+=f[i][j][1];
43 g[i+1][j*2%A][1]+=g[i][j][1];
44 }
45 else {
46 f[i+1][j*2%A][0]+=f[i][j][1];
47 g[i+1][j*2%A][0]+=g[i][j][1];
48 f[i+1][(j*2+1)%A][1]+=f[i][j][1];
49 g[i+1][(j*2+1)%A][1]+=g[i][j][1]+f[i][j][1];
50 }
51 }
52 }
53 return g[n+1][B%A][0]+g[n+1][B%A][1];
54 }
55
56 #define ANS
57 int main() {
58 #ifdef ANS
59 freopen("count.in","r",stdin);
60 freopen("count.out","w",stdout);
61 #endif
62 read(T);
63 pr[0]=1;
64 For(i,1,60) pr[i]=(pr[i-1]<<1);
65 while(T--) {
66 read(A); read(B); read(N);
67 LL ans=find(B+A*N)-find(max(0LL,B+A-1));
68 printf("%lld\n",ans);
69 }
70 Formylove;
71 }
72 /*
73 2
74 10000 5641654165416 100077775545
75 9980 14244264416 10420477545
76 */
题 2 旅游
考试的时候写了个暴力,只有20分,结果发现把题读错了,a,b都为0的点才不能经过,改过后就直接A了??数据大概是用脚造的
暴力就是把a离散,显然答案就是每种a中选一个点的序列。暴力枚举每种a的每一个点和它的前一种a中的每一个点转移。
正解我还没看懂,但是二维树状数组那个大概明白了,就是把绝对值拆开,按几种正负分别建树状数组,按a排序后,把a小的一部分加入树状数组,转移都会是一段区间,可以直接查询。
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 const int N=1007;
16 typedef long long LL;
17 typedef double db;
18 using namespace std;
19 int n,m,a[N][N],b[N][N],ls[N*N],sz;
20 LL f[N][N],ans;
21
22 template<typename T>void read(T &x) {
23 char ch=getchar(); x=0; T f=1;
24 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
25 if(ch=='-') f=-1,ch=getchar();
26 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
27 }
28
29 struct node {
30 int x,y;
31 node(){}
32 node(int x,int y):x(x),y(y){}
33 }p[N*N];
34 vector<node>vc[N*N];
35
36 LL dis(node A,node B) { return abs(A.x-B.x)+abs(A.y-B.y);}
37
38 #define ANS
39 int main() {
40 #ifdef ANS
41 freopen("tour.in","r",stdin);
42 freopen("tour.out","w",stdout);
43 #endif
44 read(n); read(m);
45 For(i,1,n) For(j,1,m) read(a[i][j]),ls[++ls[0]]=a[i][j];
46 For(i,1,n) For(j,1,m) read(b[i][j]);
47 sort(ls+1,ls+ls[0]+1);
48 sz=unique(ls+1,ls+ls[0]+1)-(ls+1);
49 For(i,1,n) For(j,1,m) {
50 if(b[i][j]==0&&a[i][j]==0) continue;
51 a[i][j]=lower_bound(ls+1,ls+sz+1,a[i][j])-ls;
52 vc[a[i][j]].push_back(node(i,j));
53 f[i][j]=b[i][j];
54 vc[a[i][j]].push_back(node(i,j));
55 }
56 For(i,2,sz) {
57 int up1=vc[i].size(),up2=vc[i-1].size();
58 For(j,0,up1-1) For(k,0,up2-1) {
59 node t1=vc[i][j],t2=vc[i-1][k];
60 f[t1.x][t1.y]=max(f[t1.x][t1.y],f[t2.x][t2.y]+dis(t1,t2)+b[t1.x][t1.y]);
61 ans=max(ans,f[t1.x][t1.y]);
62 }
63 }
64 printf("%lld\n",ans);
65 Formylove;
66 }
题 3 做梦
注意读题,每次散步总时间不能超过m,就是每次离开起点到回到起点的时间间隔不超过m。
最后只有半个小时有点方,然后脑子就很乱,都知道是dp然后矩阵优化就是没搞对,dp还瞎弄了个两维的,只得了暴力分。
预处理每一次散步的方案,定义f[i][j][k]表示从i点走k步走到j点的方案数(点从1到m),可以用floyd求出。
然后每次散步走了x步,方案数就是f[1][1][x-2]*2(第一步从0走到1或-1,再不经过0地走x-2步走回1或-1,最后一步走回0)
g[i]表示散步总步数为i的方案数,也就是n==i的答案。
$g[n]=\sum_{i=2}^{m} g[n-i]*2*f[1][1][i-2]$
这是个线性递推,矩阵加速即可。
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 const int N=107,p=1000000007;
16 typedef long long LL;
17 typedef double db;
18 using namespace std;
19 int n,m;
20 LL f[N][N][N],g[N],ans;
21
22 template<typename T>void read(T &x) {
23 char ch=getchar(); x=0; T f=1;
24 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
25 if(ch=='-') f=-1,ch=getchar();
26 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
27 }
28
29 struct jz {
30 LL a[N][N];
31 friend jz operator *(const jz&A,const jz&B) {
32 jz rs;
33 For(i,1,m) For(j,1,m) {
34 rs.a[i][j]=0;
35 For(k,1,m)
36 (rs.a[i][j]+=A.a[i][k]*B.a[k][j]%p)%=p;
37 }
38 return rs;
39 }
40 }bs,rs;
41
42 void ksm(int b) {
43 while(b) {
44 if(b&1) rs=rs*bs;
45 bs=bs*bs;
46 b>>=1;
47 }
48 }
49
50 #define ANS
51 int main() {
52 #ifdef ANS
53 freopen("dream.in","r",stdin);
54 freopen("dream.out","w",stdout);
55 #endif
56 read(n); read(m);
57 For(i,1,m) f[i][i-1][1]=1,f[i][i+1][1]=1,f[i][i][0]=1;
58 For(k,1,m) For(i,1,m) For(j,1,m) {
59 if(j-1>=1) f[i][j][k]=f[i][j-1][k-1];
60 if(j+1<=2*m+1) (f[i][j][k]+=f[i][j+1][k-1])%=p;
61 }
62 g[0]=1;
63 For(s,2,m) For(j,2,m) if(s>=j)
64 g[s]=(g[s]+g[s-j]*2LL*f[1][1][j-2]%p)%p;
65 For(i,1,m) For(j,1,m) {
66 if(i==j) rs.a[i][j]=1;
67 else rs.a[i][j]=0;
68 bs.a[i][j]=0;
69 }
70 For(i,2,m) bs.a[m-i+1][m]=2*f[1][1][i-2];
71 For(i,1,m-1) bs.a[i+1][i]=1;
72 ksm(n-1);
73 For(i,1,m)
74 ans=(ans+rs.a[i][1]*g[i]%p)%p;
75 printf("%lld\n",ans);
76 Formylove;
77 }