codechef September Challenge 2017解题报告

前记:
第一次打cc感觉要自爆啊。
(不过似乎题目非常良心啊,似乎没有撕烤题啊)

Little Chef and Sums

第一个最小值的位置。

#include <bits/stdc++.h>
#define gc getchar()
using namespace std;
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int main()
{
    int T=read();
    while (T--)
    {
        int n=read();
        int Min=1000000,pos=0;
        for (int i=1;i<=n;i++)
        {
            int x=read();
            if (x<Min) Min=x,pos=i;
        }
        printf("%d\n",pos);
    }
    return 0;
}

Minimum Good Permutation

字典序最小错排。

#include <bits/stdc++.h>
#define gc getchar()
using namespace std;
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int main()
{
    int T=read();
    while (T--)
    {
        int n=read();
        if (n&1)
        {
            for (int i=1;2*i<n-1;i++)
                printf("%d %d ",2*i,2*i-1);
            printf("%d %d %d\n",n-1,n,n-2);
        }
        else
        {
            for (int i=1;2*i<=n;i++)
                printf("%d %d%s",2*i,2*i-1,i==(n/2)?"\n":" ");
        }
    }
    return 0;
}

Chef and Pick Digit

字符串中的数字能组成哪些大写字母的ascll码

#include <bits/stdc++.h>
#define gc getchar()
#define N 100009
using namespace std;
int number[10];
char str[N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int main()
{
    int T=read();
    while (T--)
    {
        scanf("%s",str+1);
        int len=strlen(str+1);
        memset(number,0,sizeof(number));
        for (int i=1;i<=len;i++)
            number[str[i]-'0']++;
        for (int i=65;i<=90;i++)
        {
            if (i/10!=i%10)
            {
                if (number[i/10]&&number[i%10]) putchar(i);
            }
            else
            {
                if (number[i/10]>1) putchar(i);
            }
        }
        puts("");
    }
    return 0;
}

Sereja and Commands

有两种操作:
1、对 [l,r] [ l , r ] 的区间加上 a a
2、对[l,r]区间的操作再做一遍
问最后每个数的值。

因为可以离线,所以倒着跑。
如果是操作2,差分操作区间,如果是操作1,差分 a a 乘上当前操作的累计次数。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long 
#define N 100009
#define mod 1000000007
using namespace std;
int n,m,tg[N],add[N];
struct Qry
{
    int op,l,r;
}p[N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int main()
{
    int T=read();
    while (T--)
    {
        n=read(),m=read();
        for (int i=1;i<=m;i++)
            p[i].op=read(),p[i].l=read(),p[i].r=read();
        memset(tg,0,sizeof(tg));
        memset(add,0,sizeof(add));
        tg[m]=1;
        for (int i=m;i;i--)
        {
            tg[i]=(tg[i]+tg[i+1])%mod;
            if (p[i].op==1)
            {
                add[p[i].l]=(add[p[i].l]+tg[i])%mod;
                add[p[i].r+1]=(add[p[i].r+1]+mod-tg[i])%mod;
            }
            else
            {
                tg[p[i].r]=(tg[p[i].r]+tg[i])%mod;
                tg[p[i].l-1]=(tg[p[i].l-1]+mod-tg[i])%mod;
            }
        }
        int sum=0;
        for (int i=1;i<=n;i++)
        {
            sum=(sum+add[i])%mod;
            printf("%d%s",sum,i==n?"\n":" ");
        }
    }
    return 0;
}

Fill The Matrix

每个点拆成两个跑并查集就好。

#include <bits/stdc++.h>
#define gc getchar()
#define N 200009
using namespace std;
int fa[N],n,m;
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
    int xx=find(x),yy=find(y);
    if (xx!=yy) fa[xx]=yy;
}
int main()
{
    int T=read();
    while (T--)
    {
        n=read(),m=read();
        for (int i=1;i<=n*2;i++) fa[i]=i;
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read(),z=read();
            if (z==1)
            {
                merge(x,y+n);
                merge(y,x+n);
            }
            else
            {
                merge(x,y);
                merge(x+n,y+n);
            }
        }
        bool flag=1;
        for (int i=1;i<=n;i++)
            if (find(i)==find(i+n))
            {
                flag=0;
                break;
            }
        puts(flag?"yes":"no");
    }
    return 0;
}

Weasel does Xor on Tree

一个点对于根的贡献只取决于它的深度和当前天数。
显然可以每个深度一起处理。
然后会发现关系大概是个组合数(深度标准不同,写出来也不同)
之后就可以Lucas定理套用了。
算答案时需要求出形如某几位必须为0,剩余几位任意都可的val异或和,这个只要子集dp就可以了。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 200009
#define mod 1000000007
using namespace std;
int n,Q,x,y,number,first[N],deep[N],fa[N],bin[20];
ll val[N],dp[N<<1],v[N<<1];
struct edge
{
    int to,next;
    void add(int x,int y)
    {
        to=y,next=first[x],first[x]=number;
    }
}e[N<<1];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
ll Read()
{
    ll x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    ll s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10ll+ch-48;
    return s*x;
}
void dfs(int x)
{
    deep[x]=deep[fa[x]]+1;
    v[deep[x]]^=val[x];
    for (int i=first[x];i;i=e[i].next)
        if (e[i].to!=fa[x]) fa[e[i].to]=x,dfs(e[i].to);
}
int main()
{
    bin[0]=1;
    for (int i=1;i<20;i++) bin[i]=bin[i-1]<<1;
    n=read(),Q=read();
    for (int i=1;i<n;i++)
    {
        x=read()+1,y=read()+1;
        e[++number].add(x,y),e[++number].add(y,x);
    }
    for (int i=1;i<=n;i++) val[i]=Read();
    deep[0]=-1;
    dfs(1);
    for (int i=0;i<bin[18];i++)
    {
        dp[i]=v[0];
        for (int j=i;j;j=(j-1)&i) dp[i]^=v[j];
    }
    while (Q--)
    {
        ll x=Read()-1;
        if (x==-1)
        {
            printf("%lld\n",val[1]);
            continue;
        }
        int pos=0;
        for (int i=0;i<18;i++,x>>=1)
            if (!(x&1)) pos+=bin[i];
        printf("%lld\n",dp[pos]);
    }
    return 0;
}

Sum of Cubes

这题真的非常有毒。。。
直接考虑 k=3 k = 3 ,发现需要枚举各种三条边之间的关系。
其中有几种非常好算,其中有一种是三元环,这个枚举一条边,在枚举它度数较小的顶点,用map判,这样可以显然证明是 O(mmlogm) O ( m m l o g m ) 的。有一些直接算比较难的,可以通过好算的和三元环的情况容斥得到。

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 100009
#define mod 1000000007
#define pii pair<int,int>
using namespace std;
int n,m,first[N],number,ans,bin[N<<1],k,delta,d[N],sum,num,Num;
const int sed=195337;
struct hash
{
    #define mo 100007
    #define M 5000010
    int head[mo],dh[mo];
    int x[M],y[M],next[M],siz,cnt;
    inline void clear()
    {
        ++cnt,siz=0;
    }
    void ins(int _x,int _y)
    {
        int s=(1LL*_x*sed+_y)%mo;
        if (dh[s]!=cnt) dh[s]=cnt,head[s]=0;
        next[++siz]=head[s],head[s]=siz;
        x[siz]=_x,y[siz]=_y;
    }
    int count(int _x,int _y)
    {
        int s=(1LL*_x*sed+_y)%mo;
        if (dh[s]!=cnt) return 0;
        for (s=head[s];s;s=next[s])
            if (x[s]==_x&&y[s]==_y) return 1;
        return 0;
    }
}pos;
struct Edge
{
    int x,y;
}E[N];
struct edge
{
    int to,next;
    void add(int x,int y)
    {
        to=y,next=first[x],first[x]=number;
    }
}e[N<<1];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int work()
{
    int ret=0;
    for (int i=1;i<=m;i++)
        for (int j=first[E[i].x];j;j=e[j].next)
            if (pos.count(E[i].y,e[j].to)) ret++;
    ret/=3;
    return ret;
}
int main()
{
    bin[0]=1;
    for (int i=1;i<(N<<1);i++) bin[i]=(bin[i-1]<<1)%mod;
    int T=read();
    while (T--)
    {
        pos.clear();
        n=read(),m=read(),k=read();
        number=0;
        for (int i=1;i<=n;i++) first[i]=d[i]=0;
        for (int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            E[i].x=x,E[i].y=y;
            e[++number].add(x,y);
            e[++number].add(y,x);
            d[x]++,d[y]++;
            pos.ins(x,y);
            pos.ins(y,x);
        }
        for (int i=1;i<=m;i++)
            if (d[E[i].x]>d[E[i].y]) swap(E[i].x,E[i].y);
        if (k==1)
        {
            ans=(ll)m*bin[n-2]%mod;
            printf("%d\n",ans);
            continue;
        }
        if (k==2)
        {
            ans=(ll)m*bin[n-2]%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)(m-d[E[i].x]-d[E[i].y]+1)*bin[n-4]%mod)%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)(d[E[i].x]-1)*bin[n-3]%mod)%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)(d[E[i].y]-1)*bin[n-3]%mod)%mod;
            printf("%d\n",ans);
            continue;
        }
        if (k==3)
        {
            ans=(ll)m*bin[n-2]%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)3*(m-d[E[i].x]-d[E[i].y]+1)*bin[n-4]%mod)%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)3*(d[E[i].x]-1)*bin[n-3]%mod)%mod;
            for (int i=1;i<=m;i++)
                ans=(ans+(ll)3*(d[E[i].y]-1)*bin[n-3]%mod)%mod;
            num=work();
            Num=0;
            for (int i=1;i<=n;i++)
                if (d[i]>=2) Num=(Num+(ll)d[i]*(d[i]-1)/2*(m-d[i])%mod)%mod;
            for (int i=1;i<=m;i++)
                Num=(Num-(ll)2*(d[E[i].x]-1)*(d[E[i].y]-1)%mod+mod)%mod;
            Num=(Num+3*num)%mod;
            for (int i=1;i<=n;i++)
                if (d[i]>=3) ans=(ans+(ll)d[i]*(d[i]-1)%mod*(d[i]-2)%mod*bin[n-4]%mod)%mod;
            for (int i=1;i<=m;i++)
                if (n>=4) ans=(ans+(ll)6*(d[E[i].x]-1)*(d[E[i].y]-1)%mod*bin[n-4]%mod)%mod;
            sum=(ll)m*(m-1)*(m-2)/6%mod;
            for (int i=1;i<=n;i++)
                if (d[i]>=3) sum=(sum-(ll)d[i]*(d[i]-1)*(d[i]-2)/6%mod+mod)%mod;
            sum=(sum-Num+mod)%mod;
            for (int i=1;i<=m;i++)
                sum=(sum-(ll)(d[E[i].x]-1)*(d[E[i].y]-1)%mod+mod)%mod;
            sum=(sum+2*num)%mod;
            if (n>=6) ans=(ans+(ll)6*sum*bin[n-6]%mod)%mod;
            if (n>=5) ans=(ans+(ll)6*Num*bin[n-5]%mod)%mod;
            ans=(ans-(ll)6*num*bin[n-4]%mod+mod)%mod;
            printf("%d\n",ans);
            continue;
        }
    }
    return 0;
}

Weasel finds Staircase

这题在猫大指导下我先想了一个 O(kn2) O ( k n 2 ) 的dp。
先不妨假设高度递减, dp[i][j] d p [ i ] [ j ] 表示进行了 i i 次高度变化,且最后一次的阶梯高度为h[j]的到 j j 的最大面积。
然后我开始想优化,经梁大大一句话提醒,发现似乎这dp有点单调性。我们发现 j j 决策点的高度是递减的。
画了一下图,发现似乎可以cdq分治后用单调栈维护。
然后我愉快地开始敲优化,然后愉快地发现我得到了70分(wtf??)。这TM还能错小数据点??然后我就强加了O(kn2)强行过了中间30分。(所以程序到底还有什么bug啊??)

#include <bits/stdc++.h>
#define gc getchar()
#define mid (l+r>>1)
#define ll long long
#define ld long double
#define N 100009
#define inf 1e19
using namespace std;
int n,k,m,lg[N],bit[20],q[N],now,last;
vector<ll> Q;
ll dp[2][N],a[N],Min[N][20],B[N],pos[N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-48;
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-48;
    return s*x;
}
int get(int l,int r)
{
    int k=lg[r-l+1];
    return min(Min[l][k],Min[r-bit[k]+1][k]);
}
ll A(int i)
{
    return dp[last][i]+B[i];
}
ld get_k(int j,int k)
{
    if (pos[j]==pos[k]) return (ld)(A(j)<A(k))?inf:-inf;
    return (ld)(A(j)-A(k))/(pos[j]-pos[k]);
}
bool check(int x,int y,int z)
{
    return (A(x)-A(y))*(pos[y]-pos[z])>=(A(y)-A(z))*(pos[x]-pos[y]);
}
void solve(int l,int r)
{
    if (l==r) return;
    solve(l,mid);
    int Min=N;
    int head=1,tail=0,p=mid;
    for (int i=mid+1;i<=r;i++)
        if (a[i]<Min)
        {
            Min=a[i];
            while (p>=l&&a[p]>a[i])
            {
                //ins(p);
                while (tail>head&&check(q[tail-1],q[tail],p)/*get_k(q[tail-1],q[tail])>=get_k(q[tail],p)*/) tail--;
                q[++tail]=p;
                p--;
            }
            while (tail>head&&a[i]*(pos[q[tail-1]]-pos[q[tail]])<=A(q[tail-1])-A(q[tail]))
                tail--;
            if (tail>=head) dp[now][i]=max(dp[now][i],A(q[tail])+(ll)(i-pos[q[tail]]+1)*a[i]);
        }
    solve(mid+1,r);
}
int main()
{
    lg[0]=-1;
    for (int i=1;i<N;i++) lg[i]=lg[i>>1]+1;
    bit[0]=1;
    for (int i=1;i<20;i++) bit[i]=bit[i-1]<<1;
    int T=read();
    while (T--)
    {
        ll Ans=0;
        n=read(),k=read();
        if (n<=1500)
        {
            Q.clear();
            for (int i=1;i<=n;i++) a[i]=read(),Q.push_back(a[i]);
            sort(Q.begin(),Q.end());
            unique(Q.begin(),Q.end());
            for (int i=1;i<=n;i++)
                a[i]=lower_bound(Q.begin(),Q.end(),a[i])-Q.begin();
            for (int i=1;i<=n;i++) Min[i][0]=a[i];
            for (int i=1;bit[i]<=n;i++)
                for (int j=1;j+bit[i]-1<=n;j++)
                    Min[j][i]=min(Min[j][i-1],Min[j+bit[i-1]][i-1]);
            int now=0,last=1;
            memset(dp[now],0,sizeof(dp[now]));
            for (int i=1;i<=n;i++)
                for (int j=1;j<=i;j++)
                {
                    if (get(j,i)==a[i])
                        dp[now][i]=max(dp[now][i],(ll)Q[a[i]]*(i-j+1));
                    Ans=max(Ans,(ll)Q[get(j,i)]*(i-j+1));
                }
            for (int i=1;i<=k;i++)
            {
                last=now,now^=1;
                memset(dp[now],0,sizeof(dp[now]));
                for (int j=1;j<n;j++)
                {
                    int pos=0;
                    for (int r=j+1;r<=n;r++)
                        if (a[r]<a[j])
                        {
                            if (!pos) pos=r;
                            if (get(pos,r)==a[r]) dp[now][r]=max(dp[now][r],dp[last][j]+Q[a[j]]*(pos-j-1)+Q[get(pos,r)]*(r-pos+1));
                        }
                }
                for (int j=1;j<=n;j++)
                {
                    int pos=j+1;
                    ll now_ans=dp[now][j];
                    while (pos<=n&&a[pos]>=a[j]) now_ans+=Q[a[j]],pos++;
                    Ans=max(Ans,now_ans);
                }
            }
            for (int i=1;i*2<=n;i++) swap(a[i],a[n-i+1]);
            for (int i=1;i<=n;i++) Min[i][0]=a[i];
            for (int i=1;bit[i]<=n;i++)
                for (int j=1;j+bit[i]-1<=n;j++)
                    Min[j][i]=min(Min[j][i-1],Min[j+bit[i-1]][i-1]);
            now=0,last=1;
            memset(dp[now],0,sizeof(dp[now]));
            for (int i=1;i<=n;i++)
                for (int j=1;j<=i;j++)
                {
                    if (get(j,i)==a[i])
                        dp[now][i]=max(dp[now][i],(ll)Q[a[i]]*(i-j+1));
                    Ans=max(Ans,(ll)Q[get(j,i)]*(i-j+1));
                }
            for (int i=1;i<=k;i++)
            {
                last=now,now^=1;
                memset(dp[now],0,sizeof(dp[now]));
                for (int j=1;j<n;j++)
                {
                    int pos=0;
                    for (int r=j+1;r<=n;r++)
                        if (a[r]<a[j])
                        {
                            if (!pos) pos=r;
                            if (get(pos,r)==a[r]) dp[now][r]=max(dp[now][r],dp[last][j]+Q[a[j]]*(pos-j-1)+Q[get(pos,r)]*(r-pos+1));
                        }
                }
                for (int j=1;j<=n;j++)
                {
                    int pos=j+1;
                    ll now_ans=dp[now][j];
                    while (pos<=n&&a[pos]>=a[j]) now_ans+=Q[a[j]],pos++;
                    Ans=max(Ans,now_ans);
                }
            }
            printf("%lld\n",Ans);
            continue;
        }
        for (int i=1;i<=n;i++) a[i]=read();
        a[n+1]=0;
        for (int i=1;i<=n+1;i++) Min[i][0]=a[i];
        for (int i=1;bit[i]<=n+1;i++)
            for (int j=1;j+bit[i]-1<=n+1;j++)
                Min[j][i]=min(Min[j][i-1],Min[j+bit[i-1]][i-1]);
        for (int i=1;i<=n;i++)
        {
            int l=i,r=n+1,ret=i;
            while (l<=r)
            {
                if (get(i,mid)==a[i]) l=mid+1;
                else ret=mid,r=mid-1;
            }
            pos[i]=ret;
        }
        now=1,last=0;
        for (int i=1;i<=n;i++)
        {
            int l=1,r=i,ret=i;
            while (l<=r)
            {
                if (get(mid,i)==a[i]) ret=mid,r=mid-1;
                else l=mid+1;
            }
            dp[now][i]=(ll)a[i]*(i-ret+1);
            Ans=max(Ans,dp[now][i]+(ll)(pos[i]-i-1)*a[i]);
            B[i]=(ll)a[i]*(pos[i]-i-1);
        }
        for (int i=1;i<=k;i++)
        {
            last=now,now^=1;
            memset(dp[now],0,sizeof(dp[now]));
            solve(1,n);
            for (int j=1;j<=n;j++)
                Ans=max(Ans,dp[now][j]+B[j]);
        }
        for (int i=1;i*2<=n;i++) swap(a[i],a[n-i+1]);
        for (int i=1;i<=n+1;i++) Min[i][0]=a[i];
        for (int i=1;bit[i]<=n+1;i++)
            for (int j=1;j+bit[i]-1<=n+1;j++)
                Min[j][i]=min(Min[j][i-1],Min[j+bit[i-1]][i-1]);
        for (int i=1;i<=n;i++)
        {
            int l=i,r=n+1,ret=i;
            while (l<=r)
            {
                if (get(i,mid)==a[i]) l=mid+1;
                else ret=mid,r=mid-1;
            }
            pos[i]=ret;
        }
        now=1,last=0;
        for (int i=1;i<=n;i++)
        {
            int l=1,r=i,ret=i;
            while (l<=r)
            {
                if (get(mid,i)==a[i]) ret=mid,r=mid-1;
                else l=mid+1;
            }
            dp[now][i]=(ll)a[i]*(i-ret+1);
            Ans=max(Ans,dp[now][i]+(ll)(pos[i]-i-1)*a[i]);
            B[i]=(ll)a[i]*(pos[i]-i-1);
        }
        for (int i=1;i<=k;i++)
        {
            last=now,now^=1;
            memset(dp[now],0,sizeof(dp[now]));
            solve(1,n);
            for (int j=1;j<=n;j++)
                Ans=max(Ans,dp[now][j]+B[j]);
        }
        printf("%lld\n",Ans);
    }
    return 0;
}

Querying on a Grid

这题其实是比赛时看的第一道题。然后险些被吓死(好TM难)。然后梁大大看了一眼,求下一句“这就是个ZJOI2016旅行者的套路题”。然后我认真地%了一下梁大大的博客,然后终于会写了。。然后经过 n n <script type="math/tex" id="MathJax-Element-30">n</script> hours,我终于过了样例,然后交了以后,欣喜地爆零啦。然后找梁大对拍。发现自己就是个斯波,横纵坐标每天写反不知道在干什么。然后就A了。
似乎无脑分层跑dijkstra跑出最短路树就没有了吧。。(可能还有个树上到根路径加和询问单点值,这个好像dfs+树状数组就好了吧)。
(为防止特殊情况 暂时删去代码)

Sereja and Functions (Challenge)

第一次打challenge,完全不会(可能之前听梁大大说过一题)。
然后就无脑一个常数函数就没了。可能骗了42分。(可能还有一些奇奇怪怪的东西)

#include <bits/stdc++.h>
#define gc getchar()
#define ll long long
#define N 109
#define lim 100
using namespace std;
int n,b[N][N],a[N][N],num,m,Num,num2;
struct node
{
    int x,y;
    node(int x=0,int y=0):x(x),y(y){}
}p[N*N];
struct line
{
    int a1,a2,b1,b2,c1,c2,d,l,r;
    bool operator <(const line &rhs) const
    {
        return (r-l+1)<(rhs.r-rhs.l+1);
    }
    line(int a1=0,int a2=0,int b1=0,int b2=0,int c1=0,int c2=0,int d=0,int l=0,int r=0):a1(a1),a2(a2),b1(b1),b2(b2),c1(c1),c2(c2),d(d),l(l),r(r){}
}ans[N*N],Ans[N*N],Ans_now[N*N],ans2[N*N];
int read()
{
    int x=1;
    char ch;
    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
    int s=ch-'0';
    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
    return x*s;
}
void dfs(int rest,int now,int Num_now)
{
    if (Num_now>=min(num,Num)) return;
    while (now<=m&&a[p[now].x][p[now].y]>1) now++;
    if (m-now+1<=rest)
    {
        Num=Num_now;
        for (int i=1;i<=Num;i++)
            Ans[i]=Ans_now[i];
        return;
    }
    int op=rand()%1000;
    int d=max(rand()%(2*n+1)-n,p[now].y-n);
    //p[now].x*x/y+d=p[now].y
    int x=p[now].y-d,y=p[now].x;
    int use,tmp;
    if (rest==0) use=tmp=0;
    else use=rand()%min(rest,3)+1,tmp=use;
    int l=p[now].x;
    while ((l<=n)&&((a[l][l*x/y+d])||(use>0))&&(l*x/y+d>=1&&l*x/y+d<=n))
    {
        if (a[l][l*x/y+d]) a[l][l*x/y+d]++;
        else use--;
        l++;
    }
    l--;
    while (a[l][l*x/y+d]==0) l--,use++;
    Ans_now[Num_now+1]=line(0,1,0,1,x,y,d,p[now].x,l);
    dfs(rest-tmp+use,now+1,Num_now+1);
    for (int i=p[now].x;i<=l;i++)
        if (a[i][i*x/y+d]>1) a[i][i*x/y+d]--;
}
int main()
{
    srand(19260817);
    int T=read();
    while (T--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        n=read(),m=0;
        char ch;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            {
                while (ch=gc,ch!='0'&&ch!='1');
                b[i][j]=a[i][j]=ch-'0';
                if (a[i][j]) p[++m]=node(i,j);
            }
        num=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                if (a[i][j]==1)
                {
                    int x=i,y=j;
                    while (a[x][y]==1) x++,y++;
                    if (x-i>=30)
                    {
                        for (int k=i,l=j;k<x&&l<y;k++,l++)
                            a[k][l]=0;
                        ans[++num]=line(0,1,0,1,1,1,j-i,i,x-1);
                        continue;
                    }
                    if (i+j>n) continue;
                    x=i,y=j;
                    while (a[x][y]==1) x++,y--;
                    if (x-i>=30)
                    {
                        for (int k=i,l=j;k<x&&l>y;k++,l--)
                            a[k][l]=0;
                        ans[++num]=line(0,1,0,1,-1,1,i+j,i,x-1);
                        continue;
                    }
                }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                if (a[i][j]==1)
                {
                    int now=i;
                    while (a[now][j]==1) now++;
                    now--;
                    for (int k=i;k<=now;k++) a[k][j]=0;
                    ans[++num]=line(0,1,0,1,0,1,j,i,now);
                }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++) a[i][j]=b[i][j];
        num2=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                if (a[i][j]==1)
                {
                    int now=i;
                    while (a[now][j]==1) now++;
                    now--;
                    for (int k=i;k<=now;k++) a[k][j]=0;
                    ans2[++num2]=line(0,1,0,1,0,1,j,i,now);
                }
        int rest=lim;
        sort(ans+1,ans+num+1);
        int now=1;
        while (now<=num&&rest>=ans[now].r-ans[now].l+1)
            rest-=ans[now].r-ans[now].l+1,now++;
        rest=lim;
        sort(ans2+1,ans2+num2+1);
        int now2=1;
        while (now2<=num2&&rest>=ans2[now2].r-ans2[now2].l+1)
            rest-=ans2[now2].r-ans2[now2].l+1,now2++;
        if (num2-now2+1<num-now+1)
        {
            swap(num2,num);
            swap(now2,now);
            swap(ans2,ans);
        }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++) a[i][j]=b[i][j];
        Num=10000;
        for (int i=0;i<100;i++)
        {
            random_shuffle(p+1,p+m+1);
            dfs(lim,1,0);
        }
        if (Num>=num-now+1)
        {
            printf("%d\n",num-now+1);
            for (int i=now;i<=num;i++)
                printf("%d %d %d %d %d %d %d %d %d\n",ans[i].a1,ans[i].a2,ans[i].b1,ans[i].b2,ans[i].c1,ans[i].c2,ans[i].d,ans[i].l,ans[i].r);
        }
        else
        {
            printf("%d\n",Num);
            for (int i=1;i<=Num;i++)
                printf("%d %d %d %d %d %d %d %d %d\n",Ans[i].a1,Ans[i].a2,Ans[i].b1,Ans[i].b2,Ans[i].c1,Ans[i].c2,Ans[i].d,Ans[i].l,Ans[i].r);
        }
    }
    return 0;
}

后记:
似乎rank14,果然比大佬们菜到不知道哪里去了。(话说楼教主突发出现,有点害怕啊)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值