CQOI每年都这样啦。。半水不水的。。
我要在大CQ多好啊~~
T1:
第一题深搜水水的骗了55分...弱爆啊。。ORZ深搜90分。。
搜第一行就可以确定下面的行。。第一行还可以折半搜索在对称过去。。!
然后就是2^(m/2)*nm。。 然后还是要T两三个点 。。囧
不过不要紧的,BZOJ算总时间能过。。HAHAHAHA
正解:异或方程组。。待我研究研究。。
DFS版:(T3)
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
int map[45][45];
int n,m;
#define pd(i,j) (map[i][j]^map[i-1][j]^map[i][j-1]^map[i][j+1])
void check(){
rep(i,2,n) rep(j,1,m){
if (pd(i-1,j)) map[i][j]=1;
else map[i][j]=0;
}
rep(i,1,m)if (pd(n,i)) return;
rep(i,1,n) rep(j,1,m) printf("%d%c",map[i][j],j==m?'\n':' ');
exit(0);
}
void dfs1(int v){
if (v>(m+1)/2){
int mid=(m+1)/2+1;
per(i,m,mid) map[1][i]=map[1][m-i+1];
check();
return;
}
map[1][v]=1;dfs1(v+1);
map[1][v]=0;dfs1(v+1);
}
int main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%d%d",&n,&m);
dfs1(1);
}
T2:
看上去肯定是个网络流。
当时想到用满流来判断,但是不能对应a1->a2 b1->b2 可能流量是a1->b2 。。。然后,。。就没有然后了。。当场没交。。。
(后来发现这......竟然还有30分。。)
标算:先S-a1 a2-T S-b1 b2-T 连一遍跑一次。若不满流肯定无解。
若满流就再 S-a2 a1-T S-b1 b2-T 再跑一次。若不满流则无解。
若两次都满流则有解。
如果只跑一次是有BUG的,,,因为不能保证a1->a2的是an。
如果a1流a2的是an-x 那么肯定 a1->b2的是x ,b1->b2是bn-x b1->a2 是x
下面如果 b2->a2可以流x 那就可以修正路径了, a1->b2能流x b2->a2能流x 那么肯定存在a1->a2流x 。而之前又有a1->a2流an-x 那么肯定存在a1->a2流an
然后建个图随便怎么搞都行了。。。
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
#define gt getchar()
bool upmin(int &a,const int &b){return a>b?a=b,1:0;}
const int MAX_N=55;
const int INF=~0U>>1;
int first[MAX_N],next[MAX_N*MAX_N*2],to[MAX_N*MAX_N*2],f[MAX_N*MAX_N*2];
int tal;
void tjb(int x,int y,int F){
next[++tal]=first[x];
first[x]=tal,to[tal]=y,f[tal]=F;
next[++tal]=first[y];
first[y]=tal,to[tal]=x,f[tal]=0;
}
int pre[MAX_N],cur[MAX_N],his[MAX_N],dis[MAX_N],gap[MAX_N];
int sap(int S,int T){
rep(i,S,T) cur[i]=first[i],dis[i]=gap[i]=0;
int u=pre[S]=S;
int aug=INF,maxflow=0;
int Size=T-S+1;
gap[0]=Size;
while (dis[S]<Size){
his[u]=aug;
for (int& k=cur[u];k;k=next[k])
if (f[k]&&dis[u]==dis[to[k]]+1) break;
if (cur[u]){
int v=to[cur[u]];
upmin(aug,f[cur[u]]);
pre[v]=u,u=v;
if (u==T){
maxflow+=aug;
while (u!=S) u=pre[u],f[cur[u]]-=aug,f[cur[u]^1]+=aug;
aug=INF;
}
}else{
int mindis=Size;
for (int k=first[u];k;k=next[k])
if (f[k]&&upmin(mindis,dis[to[k]]+1)) cur[u]=k;
if (!--gap[dis[u]]) break;
++gap[dis[u]=mindis];
u=pre[u],aug=his[u];
}
}
return maxflow;
}
char map[MAX_N][MAX_N];
int n,a1,a2,an,b1,b2,bn,S,T;
void mkgraph(){
std::fill(first,first+n+10,0);tal=1;
tjb(S,a1+1,an),tjb(a2+1,T,an);
tjb(S,b1+1,bn),tjb(b2+1,T,bn);
rep(i,1,n) rep(j,1,n){
if (map[i][j]=='N') tjb(i,j,INF);
if (map[i][j]=='O') tjb(i,j,1);
}
}
int main(){
freopen("bridge.in","r",stdin);
freopen("bridge.out","w",stdout);
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF){
S=0,T=n+1;
rep(i,1,n) rep(j,1,n){
char& t=map[i][j];
for (t=gt;t!='X'&&t!='N'&&t!='O';t=gt);
}
mkgraph();
if (sap(S,T)!=an+bn){printf("No\n");continue;}
std::swap(a1,a2);
mkgraph();
if (sap(S,T)!=an+bn){printf("No\n");continue;}
printf("Yes\n");
}
}
T3:
这题A掉了。。
首先可以C(n*m,3) 。。然后再减掉不行的情况。
不行->只有三点共线
所以考虑找到每一条极长直线中有多少个点。然后再减一下就行了。
由于n、m<=1000
我们可以枚举直线(枚举一个矩形长宽,对角线是我们想要的线段,矩形的长宽Gcd+1就是这条线段上的点数。)
然后令s[n]表示 线段上有n个点 的线段条数
注意到这不是极长的。但是 若 一条线段上有n个点 那么他肯定包含2条n-1个点的线段 3条n-2的线段。。。
然后就可以倒推出有n个点的极长线段的条数。。
然后再组合一下就行了。。
后面发现我这方法有点沙茶了。。
直接枚举线段,,然后我们必选这个线段的端点,然后端点中间的点随便选,个数就是Gcd-1。
然后不会重复直接减掉就行了。。
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
typedef long long LL;
int Gcd(int a,int b){return b?Gcd(b,a%b):a;}
const int MAX_N=1050;
int n,m;
LL C[MAX_N][5];
void getC(){
int p=n>m?n:m;
rep(i,0,p) C[i][0]=1;
rep(i,1,p) rep(j,1,3) C[i][j]=C[i-1][j-1]+C[i-1][j];
}
LL num[MAX_N];
LL calc(){
LL res=0;
rep(i,1,n) rep(j,1,m){
int s=(n-i+1)*(m-j+1);
int g=Gcd(i-1,j-1)+1;
num[g]+=((i==1||j==1)?1:2)*s;
}
int p=n>m?n:m;
per(i,p,1) rep(j,i+1,p) num[i]-=(j-i+1)*num[j];
rep(i,3,p) res+=C[i][3]*num[i];
return res;
}
int main(){
freopen("triangle.in","r",stdin);
freopen("triangle.out","w",stdout);
scanf("%d%d",&n,&m);n++,m++;
getC();
LL ans=(LL)(n*m)*(n*m-1)*(n*m-2)/6-calc();
printf("%I64d\n",ans);
}
T4:
逗比了。。
没想到如何找最小值的位置啊。。。
泰沙茶 了。。。 记录最小值的节点编号。 然后splay那个节点到根,然后左儿子size+1.....
蒟蒻。。。
以前写splay都是先用size找的时候就downdata了。。
但是这个直接splay一个点,必须先把上面的data全部down下来才行!
然后好像rotate的时候就不用down了??!
downdata可以用dfs来做。。要从上而下。。虽然我之前傻傻地开了个数组来记preprepreprepre...
#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
const int MAX_N=100050;
const int INF=~0U>>1;
int getx(){
char c;int x;
for (c=getchar();c<'0'||c>'9';c=getchar());
for (x=0;c>='0'&&c<='9';c=getchar())
x=(x<<3)+(x<<1)+c-'0';
return x;
}
struct ND{int c,v;} value[MAX_N];
bool operator <(const ND &a,const ND &b){return a.c<b.c||(a.c==b.c&&a.v<b.v);}
int a[MAX_N],n;
int pre[MAX_N],ch[MAX_N][2],tal=0;
int size[MAX_N];
ND r[MAX_N],min[MAX_N];
bool rev[MAX_N];
int root;
void up(int x){
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
min[x]=min[ch[x][0]]<min[ch[x][1]]?min[ch[x][0]]:min[ch[x][1]];
min[x]=min[x]<r[x]?min[x]:r[x];
}
void down(int x){
if (rev[x]){
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x]=0;
std::swap(ch[x][0],ch[x][1]);
}
}
void Rotate(int x,int f){
int y=pre[x];
down(x),down(y); //似乎可以不要了吧
ch[y][!f]=ch[x][f];
pre[ch[x][f]]=y;
ch[x][f]=y;
pre[x]=pre[y];
pre[y]=x;
if (pre[x]) ch[pre[x]][ch[pre[x]][1]==y]=x;
up(y);
}
void pdown(int x){
if (!x) return;
pdown(pre[x]);down(x);
}
//int fa[MAX_N],top,p;
void splay(int x,int goal){
//for (top=0,p=x;p;p=pre[p]) fa[++top]=p;
//per(i,top,1) down(fa[i]);
pdown(x);
while(pre[x]!=goal){
if (pre[pre[x]]==goal)
Rotate(x,ch[pre[x]][0]==x);
else{
int y=pre[x],z=pre[y];
int f=(ch[z][0]==y);
if (ch[y][f]==x)
Rotate(x,!f),Rotate(x,f);
else
Rotate(y,f),Rotate(x,f);
}
}
up(x);
if (goal==0) root=x;
}
void RTO(int x,int goal){
int v=root;
for (;v;){
down(v);
int tp=size[ch[v][0]]+1;
if (tp==x) break;
if (tp<x) x-=tp,v=ch[v][1];
else v=ch[v][0];
}
down(v);
splay(v,goal);
}
void range(int l,int r){
RTO(l,0);RTO(r+2,root);
}
void Newn(int &v,int p,int fa){
v=++tal;
r[v]=min[v]=(ND){a[p],v};
size[v]=1;pre[v]=fa;
rev[v]=0;
}
void build(int &v,int l,int r,int fa){
if (l>r) return;
int mid=l+r>>1;
Newn(v,mid,fa);
build(ch[v][0],l,mid-1,v);
build(ch[v][1],mid+1,r,v);
up(v);
}
ND qmin(int L,int R){
range(L,R);
return min[ch[ch[root][1]][0]];
}
void reverse(int L,int R){
range(L,R);
rev[ch[ch[root][1]][0]]^=1;
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
min[0].c=INF;
n=getx();
rep(i,1,n) value[i]=(ND){getx(),i};
std::sort(value+1,value+n+1);
rep(i,1,n) a[value[i].v]=i;
per(i,n,1) a[i+1]=a[i];
build(root,1,n+2,0);
ND tp;
rep(i,1,n){
tp=qmin(i,n);
splay(tp.v,0);
printf("%d%c",size[ch[root][0]],i==n?'\n':' ');
reverse(i,size[ch[root][0]]);
}
}
T5:
第一眼: 这不是冬令营的什么自动机吗。。什么DFANFA。。。
然后就模拟了一遍。。。
然后就木有然后了。。30分算法还WA了个点。。沙茶代码就不发了。。现在还没做呢。。