又是一周总结时间~中间有一周停了是因为本弱去准备考试了。下星期就是GDOI了,本弱还是去旅游!比赛什么的……蒟蒻早已准备退役了。
20160418:
1、bzoj3223 http://www.lydsy.com/JudgeOnline/problem.php?id=3223
题意:一个数列,支持区间翻转操作。
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define fa(x) nds[x].fa 6 #define ch(x,y) nds[x].ch[y] 7 #define tg(x) nds[x].tg 8 #define v(x) nds[x].v 9 #define sz(x) nds[x].sz 10 using namespace std; 11 12 struct nd{int fa,ch[2],v,sz,tg;}; 13 nd nds[200000]; int size,root,n,m; bool first; 14 void pushdown(int x){ 15 if(! x)return; if(tg(x)){ 16 if(ch(x,0)&&ch(x,1))swap(ch(x,0),ch(x,1)),tg(ch(x,0))^=1,tg(ch(x,1))^=1;else 17 if(ch(x,0))ch(x,1)=ch(x,0),ch(x,0)=0,tg(ch(x,1))^=1;else ch(x,0)=ch(x,1),ch(x,1)=0,tg(ch(x,0))^=1; 18 tg(x)^=1; 19 } 20 } 21 void update(int x){if(! x)return; sz(x)=sz(ch(x,0))+sz(ch(x,1))+1;} 22 void rotate(int x){ 23 if(x==0||fa(x)==0)return; 24 int a1=fa(x),a2=fa(a1); bool a3=(x==ch(a1,1)),a4=(a1==ch(a2,1)); 25 if(a2)ch(a2,a4)=x; if(ch(x,!a3))fa(ch(x,!a3))=a1; ch(a1,a3)=ch(x,!a3); ch(x,!a3)=a1; 26 fa(x)=a2; fa(a1)=x; update(a1); update(x); if(a2)update(a2); 27 } 28 void splay(int x,int y){ 29 if(x==0||y==0)return; int z=fa(y); if(y==root)root=x; 30 while(fa(x)!=z){ 31 if(fa(fa(x))!=z){ 32 if((x==ch(fa(x),1))^(fa(x)==ch(fa(fa(x)),1)))rotate(x);else rotate(fa(x)); 33 } 34 rotate(x); 35 } 36 } 37 int build(int l,int r){ 38 if(l>r)return 0; 39 ++size; int ff=size; int m=(l+r)>>1; ch(ff,0)=build(l,m-1); ch(ff,1)=build(m+1,r); 40 if(ch(ff,0))fa(ch(ff,0))=ff; if(ch(ff,1))fa(ch(ff,1))=ff; 41 v(ff)=m; tg(ff)=0; update(ff); return ff; 42 } 43 int find(int p){ 44 int x=root; while(1){ 45 if(x==0)return 0; pushdown(x); 46 int a1=sz(ch(x,0)); if(a1+1==p)return x; 47 if(a1+1<p)p-=(a1+1),x=ch(x,1);else x=ch(x,0); 48 } 49 } 50 void rever(int l,int r){ 51 int a1=find(l-1),a2=find(r+1); splay(a2,root); 52 if(l>1)splay(a1,ch(a2,0)),tg(ch(a1,1))^=1;else tg(ch(a2,0))=1; 53 } 54 void print(int x){ 55 if(x==0)return; pushdown(x); 56 print(ch(x,0)); 57 if(v(x)!=n+1) 58 if(!first)printf("%d",v(x)),first=1;else printf(" %d",v(x)); 59 print(ch(x,1)); 60 } 61 int main(){ 62 //freopen("test.txt","r",stdin); 63 scanf("%d%d",&n,&m); size=0; root=build(1,n+1); 64 inc(i,1,m){ 65 int a,b; scanf("%d%d",&a,&b); rever(a,b); 66 } 67 first=0; print(root); 68 return 0; 69 }
题解:splay裸题。注意涉及到区间操作的一般用splay不用treap。
2、bzoj2299 http://www.lydsy.com/JudgeOnline/problem.php?id=2299
题意:有(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问能否拼出另一个向量(x,y)。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 long long gcd(long long a,long long b){return b==0?a:gcd(b,a%b);} 7 inline bool check(long long x,long long y,long long z){return x%z==0&&y%z==0;} 8 int main(){ 9 int t; scanf("%d",&t); 10 while(t--){ 11 long long a,b,x,y; scanf("%lld%lld%lld%lld",&a,&b,&x,&y); 12 long long c=gcd(2*a,2*b); 13 if(check(x,y,c)||check(x+a,y+b,c)||check(x+b,y+a,c)||check(x+a+b,y+a+b,c))puts("Y");else puts("N"); 14 } 15 return 0; 16 }
题解:裴蜀定理(我不会)(实际上是与解同余方程的知识相关的)。题目可以转化为用(0,2a)、(2a,0)、(0,2b)、(2b,0)拼成(x,y)、(x+a,y+b)、(x+b,y+a)、(x+a+b,y+a+b)。这样就可以列方程了。题目要求判断方程是否有解,只要求出2a、2b的gcd,然后判断目标两个数能否整除这个gcd即可。
3、bzoj3442 http://www.lydsy.com/JudgeOnline/problem.php?id=3442
题意:共有n个学生,m个学习小组,每个学生只愿意参加其中的一些学习小组,且一个学生最多参加k个学习小组。每个学生参加学习小组财务处都收一定的手续费,不同的学习小组有不同的手续费。若有a个学生参加第i个学习小组,财务处支付奖励Ci*a^2元。在参与学生(而不是每个学习小组的人数总和)尽量多的情况下,求财务处最少要支出多少钱。
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define visit(i,j) for(int i=g[j];i!=-1;i=es[i].n) 7 #define INF 0x3fffffff 8 using namespace std; 9 10 struct e{int f,t,c,w,n;}; e es[1000000]; int ess,g[400]; 11 void pe(int f,int t,int c,int w){ 12 es[++ess]=(e){f,t,c,w,g[f]}; g[f]=ess; es[++ess]=(e){t,f,0,-w,g[t]}; g[t]=ess; 13 } 14 void init(){ess=-1; memset(g,-1,sizeof(g));} 15 int d[400],fr[400]; queue <int> q; bool inq[400],vis[400]; 16 bool spfa(int s,int t){ 17 while(! q.empty())q.pop(); memset(inq,0,sizeof(inq)); memset(vis,0,sizeof(vis)); 18 inq[s]=1; d[s]=0; vis[s]=1; q.push(s); 19 while(! q.empty()){ 20 int x=q.front(); q.pop(); inq[x]=0; 21 visit(i,x)if(es[i].c&&(! vis[es[i].t]||d[es[i].t]>d[x]+es[i].w)){ 22 d[es[i].t]=d[x]+es[i].w; vis[es[i].t]=1; fr[es[i].t]=i; 23 if(! inq[es[i].t])inq[es[i].t]=1,q.push(es[i].t); 24 } 25 } 26 if(! vis[t])return 0;else return 1; 27 } 28 int advanced(int s,int t){ 29 int a=INF; for(int i=t;i!=s;i=es[fr[i]].f)a=min(a,es[fr[i]].c); 30 int cost=0; for(int i=t;i!=s;i=es[fr[i]].f)es[fr[i]].c-=a,es[fr[i]^1].c+=a,cost+=(es[fr[i]].w*a); 31 return cost; 32 } 33 int maxflowmincost(int s,int t){ 34 int cost=0; while(spfa(s,t)) 35 cost+=advanced(s,t); return cost; 36 } 37 int n,m,k,s,t,a1[400]; char a3[400]; 38 int main(){ 39 //freopen("test.txt","r",stdin); 40 scanf("%d%d%d",&n,&m,&k); s=0; t=n+m+1; init(); inc(i,1,n)pe(s,i,k,0),pe(i,t,k-1,0); 41 inc(i,n+1,n+m){int a2; scanf("%d",&a2); inc(j,1,n)pe(i,t,1,(j*2-1)*a2);} 42 inc(i,1,m)scanf("%d",&a1[i]); inc(i,1,n){ 43 scanf("%s",a3); inc(j,1,m){if(a3[j-1]==‘1‘)pe(i,n+j,1,-a1[j]);} 44 } 45 printf("%d",maxflowmincost(s,t)); 46 return 0; 47 }
题解:s连n个学生,流量为k,费用为0。每个学生向喜欢的小组的连边,流量为1,费用为手续费的相反数。每个小组向t连边,它的费用与流量的平方成正比的边,需要把它拆成k条流量为1,费用为1*ci、3*ci…(2*k-1)的边。本题的难点是要参与学生尽量多,所以我们需要每个学生至少参加一个组,因此每个学生再向t连一条流量为k-1,费用为0的边,就可以了。
4、bzoj2751 http://www.lydsy.com/JudgeOnline/problem.php?id=2751
题意:已知一个数列A对于所有的A[i]都是1~n的自然数,一些A[i]不能取一些值,求出所有可能的数列的积的和 mod 1000000007的值。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define ll long long 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define mod 1000000007 7 using namespace std; 8 9 struct nd{ 10 ll a,b; 11 bool operator < (const nd &c)const{ 12 if(a!=c.a)return a<c.a;else return b<c.b; 13 } 14 }; 15 ll power(ll a,ll b){ 16 if(b==0)return 1; if(b==1)return a; ll c=power(a,b>>1)%mod; 17 if(b&1)return c*c%mod*a%mod;else return c*c%mod; 18 } 19 nd ns[200000]; 20 int main(){ 21 ll n,m,a1=0,a2,a3,a4; ll k; scanf("%lld%lld%lld",&n,&m,&k); 22 inc(i,1,k)scanf("%lld%lld",&ns[i].a,&ns[i].b); sort(ns+1,ns+k+1); 23 inc(i,1,k)if(i==1||ns[i].a!=ns[i-1].a)a1++; a2=n*(n+1)/2%mod; a3=a4=1; 24 inc(i,1,k)if(i==1||ns[i].a!=ns[i-1].a)a4=a4*a3%mod,a3=a2,a3=(a3-ns[i].b)>=0?(a3-ns[i].b)%mod:(a3-ns[i].b)+mod; 25 else if(ns[i].b!=ns[i-1].b)a3=(a3-ns[i].b)>=0?(a3-ns[i].b)%mod:(a3-ns[i].b)+mod; 26 a4=a4*a3%mod; a4=a4*power(a2,m-a1)%mod; printf("%lld",a4); 27 }
题解:题目中的n≤109实际上是109……首先推个方程s[l,r]=s[l,k]*s[k+1,r](s[l,r]表示l到r的所有l≤i≤r的a[i]的可能取值的和)因此s[1,n]等于所有a[i]的可能取值的和的乘积。因此我们先求出1到n的和,对每个约束条件按i排序,将这个和减掉约束条件中的不能取的数,就是这个a[i]所有可能取值的和。将这些a[i]乘起来,剩下的没限制的a[i]用快速幂解决。
5、bzoj2843 http://www.lydsy.com/JudgeOnline/problem.php?id=2843
题意:一些点,每个点有一个权值。有三种操作:点与点连边,单点修改权值,求两点之间路径上点的权值和(需要判输入是否合法)
6、bzoj2429 http://www.lydsy.com/JudgeOnline/problem.php?id=2429
题意:平面上N个点(任意两个点的坐标都不相同)。现已知M个猴子的最大跳跃距离,还知道N个点坐标,统计有多少个猴子可以在所有点上觅食。
7、bzoj2428 http://www.lydsy.com/JudgeOnline/problem.php?id=2428
题意:已知N个正整数,将它们分成M组,使各组数据的数值和最平均,即各组的均方差最小,求最小均方差。
其中σ为均方差,-x-是各组数据和的平均值,xi为第i组数据的数值和。
8、bzoj4514 http://www.lydsy.com/JudgeOnline/problem.php?id=4514
题意:有 n 种数字,第 i 种数字是 ai、有 bi 个,权值是 ci。若两个数字 ai、aj 满足ai 是 aj 的倍数且 ai/aj 是一个质数,那么这两个数字可以配对,并获得 ci×cj 的价值。一个数字只能参与一次配对,可以不参与配对。在获得的价值总和不小于 0 的前提下,求最多进行多少次配对。
9、bzoj2049 http://www.lydsy.com/JudgeOnline/problem.php?id=2049
题意:一些点,三种操作:点与点连边、点与点分离、询问两个点是否连通。
10、bzoj4518 http://www.lydsy.com/JudgeOnline/problem.php?id=4518
题意:n个数,分成m段使每段和的方差尽可能小。设方差是v,可证v×(m^2)是一个整数。输出v×(m^2)。
11、bzoj1264 http://www.lydsy.com/JudgeOnline/problem.php?id=1264
题意:某种序列由n种数组成,每种数在该序列中正好出现5次。对于两个这样的序列s1和s2,如果存在一个序列u同时成为s1和s2的子序列,则称u是s1和s2的公共子序列。子序列的概念:若从一个序列s中任意抽取一些数字,将它们仍按在s中的顺序排列成一个新串u,则称u是s的一个子序列。已知两个等长DNA序列s1和s2,求s1和s2最长公共子序列的长度。