20160327~20160402
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20160327~20160402相关的知识,希望对你有一定的参考价值。
蒟蒻太弱了,一星期刷这么少。
20160329:
1、bzoj1087 http://www.lydsy.com/JudgeOnline/problem.php?id=1087
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 using namespace std; 6 7 long long x[100][10000],y[100][10000],n,k; 8 inline bool bit(int x,int y){return x&(1<<(y-1));} 9 inline int set(int x,int y,bool z){ 10 if(z)return x|(1<<(y-1));else return x&((1<<(n+1))-1-(1<<(y-1))); 11 } 12 int main(){ 13 scanf("%d%d",&n,&k); x[k][0]=1; 14 inc(i1,1,n)inc(j1,1,n){ 15 inc(i2,0,k)inc(j2,0,(1<<(n+1))-1)y[i2][j2]=0; 16 inc(i2,0,k)inc(j2,0,(1<<(n+1))-1){ 17 if(i2&&(j1==1||(! bit(j2,j1-1)))&&(i1==1||(! bit(j2,j1)))&&(i1==1||j1==1||(! bit(j2,n+1)))&&(j1==n||(! bit(j2,j1+1)))) 18 y[i2-1][set(set(j2,n+1,bit(j2,j1)),j1,1)]+=x[i2][j2]; 19 y[i2][set(set(j2,n+1,bit(j2,j1)),j1,0)]+=x[i2][j2]; 20 }swap(x,y); 21 } 22 long long ans=0; inc(i,0,(1<<(n+1))-1)ans+=x[0][i]; printf("%lld",ans); 23 return 0; 24 }
题解:状压dp。我的做法是像插头dp那样保存当前列右侧的上一行和当前列左侧的当前行的情况,同时加一列存左上角的状态,逐格递推,滚动掉行列的状态表示。过倒是过了然而是状态版上的倒数第一。我状压dp递推的时候不知道怎么省状态,可能写记忆化搜索会快一些,但就不能滚动了。
20160331:
2、bzoj1257 http://www.lydsy.com/JudgeOnline/problem.php?id=1257
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 #define inc(i,j,k) for(long long i=j;i<=k;i++) 6 using namespace std; 7 8 int main(){ 9 long long n,k; scanf("%lld%lld",&n,&k); long long ans=0; 10 long long sz=(long long)sqrt(k)+1; 11 if(n<=sz){ 12 inc(i,1,n)ans+=k%i; 13 }else{ 14 inc(i,1,sz)ans+=k%i; 15 inc(j,1,k/sz){ 16 long long l=max(k/(j+1)+1,sz+1),r=min(min(k/j,k),n); if(l>r)continue; 17 ans+=(k*(r-l+1)-j*(l+r)*(r-l+1)/2); 18 } 19 if(n>k)ans+=k*(n-k); 20 } 21 printf("%lld",ans); 22 return 0; 23 }
题解:思路很巧妙。先划分一下,第一步对≤√k的n暴力求。因为a%b也对于a-a div b(用pascal的术语,表整除)*b,所以第二步对于1到√k的每个数i,求一个区间[l,r]使得区间里每个数被k整除后商为i,然后就可以用数列求和公式求k div [l,r]*[l,r]的和,再用k减后做个累加即可,但要注意区间不要和之前在第一步求过的重叠。对大于k的n直接做乘法,因为一个数%大于自己的数等于自己。
20160401:
3、bzoj1303 http://www.lydsy.com/JudgeOnline/problem.php?id=1303
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define dec(i,j,k) for(int i=j;i>=k;i--) 6 using namespace std; 7 8 int l[400000],r[400000],s,n,b,a[200000],p; 9 int main(){ 10 scanf("%d%d",&n,&b); 11 inc(i,1,n){ 12 int a1; scanf("%d",&a1); if(a1==b)a[i]=0,p=i; if(a1<b)a[i]=-1; if(a1>b)a[i]=1; 13 } 14 l[p+1]=0; dec(i,p,1)l[i]=l[i+1]+a[i]; 15 memset(r,0,sizeof(r)); s=0; inc(i,p,n)s=s+a[i],r[s+n]++; 16 int ans=0; inc(i,1,p)ans+=r[-l[i]+n]; 17 printf("%d",ans); 18 }
题解:首先将数组中所有小于b的数置为-1,等于的置为0,大于的置为1。然后对b及其右边的数的前缀和(b的位置到该位置所有数的和)出现个数建一个数组r,对b左边的数的每个后缀和(该位置到b的位置所有数的和)的相反数在r中的数相乘就是答案。实际上,这种把数转化成1、-1、0的方法十分常用,但是我不会。
4、bzoj1143 http://www.lydsy.com/JudgeOnline/problem.php?id=1143
见专门题解:网络流
5、bzoj1202 http://www.lydsy.com/JudgeOnline/problem.php?id=1202
以上是关于20160327~20160402的主要内容,如果未能解决你的问题,请参考以下文章