hdu多校第四场题解(>=100人)

版权声明:转载之前请说你是博主的粉丝哦。 https://blog.csdn.net/qq_34921856/article/details/82120547

B - Problem B. Harvest of Apples
这题是个好题。一开始我以为有什么公式可以直接套,然后就没多想就去找题解了,结果题解说是莫队,突然觉得很有道理。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;

//***************************************************
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extgcd(long long a,long long b,long long &x,long long &y)
{
    if(a==0&&b==0)return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    long long d=extgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;//返回gcd(a,b)
}
//****************求逆元******************************
//ax=1(mod n)
long long mod_reverse(long long a,long long n)
{
    long long x,y;
    long long d=extgcd(a,n,x,y);
    if(d==1)return (x%n+n)%n;
    return -1;
}


long long tab1[maxn],tab2[maxn];
void init()
{
    tab1[0]=1;
    for(int i=1;i<maxn;i++)
        tab1[i]=tab1[i-1]*i%mod;
    tab2[maxn-1]=mod_reverse(tab1[maxn-1],mod);
    for(int i=maxn-2;i>=0;i--)
        tab2[i]=tab2[i+1]*(i+1)%mod;
}

long long C(int a,int b)
{
    if(a<b)return 0;
    return tab1[a]*tab2[b]%mod*tab2[a-b]%mod;
}
//
const int maxm=1e5+5;
int len;
struct Query
{
    int L,R,block;
    int idx;
    Query(int l,int r,int i):L(l),R(r),idx(i)
    {
        block=L/len;
    }
    Query(){}
    bool operator<(const Query &b)const
    {
        if(block!=b.block)return block<b.block;
        return R<b.R;
    }
};
Query q[maxm];
long long ans[maxm];
int main()
{
    init();
    len=sqrt(1e5);
    int T;
    scanf("%d",&T);
    int n,m;
    for(int t=1;t<=T;t++)
    {
        scanf("%d %d",&n,&m);
        q[t]=Query(m,n,t);
    }
    sort(q+1,q+1+T);
    int L=1,R=1;
    long long tmpans=2;
    long long inv2=mod_reverse(2,mod);
    for(int i=1;i<=T;i++)
    {
        Query tmp=q[i];
        while(R<tmp.R)
        {
            tmpans=((2LL*tmpans%mod-C(R,L))%mod+mod)%mod;
            R++;
        }
        while(L>tmp.L)
        {
            tmpans=((tmpans-C(R,L))%mod+mod)%mod;
            L--;
        }
        while(R>tmp.R)
        {
            R--;
            tmpans=(tmpans+C(R,L))%mod*inv2%mod;
        }
        while(L<tmp.L)
        {
            L++;
            tmpans=(tmpans+C(R,L))%mod;
        }
        ans[tmp.idx]=tmpans;
    }
    for(int t=1;t<=T;t++)
    {
        printf("%lld\n",ans[t]);
    }
    return 0;

}

E - Problem E. Matrix from Arrays
这题规律到是好找,但写的时候想多了,写的有点复杂,结果比赛的时候没过。。
实际上对于每个点求前缀和,然后和往常一样加加减减就行了。

#include<bits/stdc++.h>
using namespace std;
int M[105][105];
int A[15];
int L;
void init()
{
    int cursor=0;
    for(int i=0; i<100; i++)
        for(int j=0; j<=i; j++)
        {
            M[j][i-j]=A[cursor];
            cursor=(cursor+1)%L;
        }

    /*for(int i=0; i<20;i++)
    {
        for(int j=0; j<20; j++)
        {
            printf("%-3d ",M[i][j]);
        }
        cout<<endl;
    }
    int res=0;
    for(int i=5;i<=14;i++)
        for(int j=3;j<=14;j++)
            res+=M[i][j];
    cout<<res<<endl;
    */for(int i=0; i<2*L; i++)
    {
        for(int j=0; j<2*L; j++)
        {
            if(i==0&&j==0)
                continue;
            if(i==0)M[i][j]+=M[i][j-1];
            else if(j==0)M[i][j]+=M[i-1][j];
            else M[i][j]=M[i][j]+M[i-1][j]+M[i][j-1]-M[i-1][j-1];
        }
    }
}

int getsum(int x1,int y1,int x2,int y2)
{
    if(x1==0&&y1==0)
        return M[x2][y2];
    else if(x1==0)
        return M[x2][y2]-M[x2][y1-1];
    else if(y1==0)
        return M[x2][y2]-M[x1-1][y2];
    return M[x2][y2]-M[x1-1][y2]-M[x2][y1-1]+M[x1-1][y1-1];
}

long long f(int x,int y)
{
    int tmp1=x/(2*L),tmp2=y/(2*L);
    long long res=1LL*tmp1*tmp2*getsum(0,0,2*L-1,2*L-1);
    res=res+1LL*tmp1*getsum(0,0,2*L-1,y%(2*L));
    res=res+1LL*tmp2*getsum(0,0,x%(2*L),2*L-1);
    res=res+getsum(0,0,x%(2*L),y%(2*L));
    return res;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&L);
        for(int i=0; i<L; i++)scanf("%d",&A[i]);
        init();

        int Q;
        scanf("%d",&Q);
        int x1,y1,x2,y2;
        while(Q--)
        {
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            long long sum=0;
            sum=f(x2,y2);
            if(x1)sum-=f(x1-1,y2);
            if(y1)sum-=f(x2,y1-1);
            if(x1&&y1)sum+=f(x1-1,y1-1);
            printf("%lld\n",sum);
        }
    }
    return 0;
}

J - Problem J. Let Sudoku Rotate
这题也是直接看题解了。。我是傻逼再看题解。
由于数独的特性,加个判断当前的旋转是否可行就能减少复杂度,然后直接爆搜就完事了。

#include<bits/stdc++.h>
using namespace std;
char s[20][20];
int ans;
char tmp[20];
void rotate(int x,int y)
{
    x=4*(x-1)+1;
    y=4*(y-1)+1;
    int now=0;
    for(int i=y;i<=y+3;i++)
    {
        for(int j=x+3;j>=x;j--)
            tmp[++now]=s[j][i];
    }
    now=0;
    for(int i=x;i<=x+3;i++)
        for(int j=y;j<=y+3;j++)
            s[i][j]=tmp[++now];
}
bool vis[30];
bool ok(int x,int y)
{
    x=4*x,y=4*y;
    for(int i=1;i<=x;i++)
    {
        memset(vis,0,sizeof(vis));
        for(int j=1;j<=y;j++)
        {
            char tmp=s[i][j];
            if(tmp>='0'&&tmp<='9')tmp-='0';
            else tmp-='A',tmp+=10;
            if(vis[tmp])return 0;
            vis[tmp]=1;
        }
    }
    for(int i=1;i<=y;i++)
    {
        memset(vis,0,sizeof(vis));
        for(int j=1;j<=x;j++)
        {
            char tmp=s[j][i];
            if(tmp>='0'&&tmp<='9')tmp-='0';
            else tmp-='A',tmp+=10;
            if(vis[tmp])return 0;
            vis[tmp]=1;
        }
    }
    return 1;
}

void dfs(int x,int y,int res)
{
    if(x==5)
    {
        ans=min(ans,res);
        return;
    }
    int nxtx=x,nxty=y+1;
    if(nxty==5)
    {
        nxty=1;nxtx++;
    }
    for(int i=0;i<4;i++)
    {
        if(i)rotate(x,y);
        if(ok(x,y))
            dfs(nxtx,nxty,res+i);
    }
    rotate(x,y);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        for(int i=1;i<=16;i++)
            scanf("%s",s[i]+1);
        ans=1000;
        dfs(1,1,0);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/82120547
今日推荐