文章标题

T1

LGTB 与序列
LGTB 得到了一个序列,他想在这个序列中选择一个最长的连续子序列,使得这个子序列的最大公约数等于
1。请告诉他他能得到的最大长度,如果没有这样的序列,输出��1
输入
输入第一行包含一个整数n 代表序列大小
接下来一行,包含n 个整数a1, a2, …, an,代表序列
对于50% 的数据,1 n 1000
对于100% 的数据,1 n 105 1 ai 109
输出
输出包含一个整数l,代表最长的连续子序列,如果无解请输出��1
样例
样例输入
2
7 2
样例输出
2
样例输入
3
2 2 4
样例输出
-1

一道水题…不过我不太懂n=1的时候答案居然是1?excuse me?
代码:

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int N=1e5+5;
int n,s[N],ans;
int gcd(int a,int b)
{
    if(!b)return a;
    else return gcd(b,a%b);
}
void worrk()
{
    int hs=s[1];
    for(int i=2;i<=n;i++)
    {
        hs=gcd(hs,s[i]);
        if(hs==1){ans=n;return;}
    }
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    scanf("%d",&n);ans=-1;
    for(int i=1;i<=n;i++)
        scanf("%d",&s[i]);
    worrk();
    printf("%d",ans);
    return 0;
}

T2

LGTB 与桌子
LGTB 新买了一张n m 的矩(桌) 阵(子),他想给某些1 1 的小矩形染色,使得染色之后,原矩阵的每
个n n 的子矩阵中都包含恰好k 个被染色了的小矩形
他想知道有多少种染色方案能让他满足上述要求
因为答案可能很大,请输出方案数模1000000007 (109 + 7) 后的值
输入
输入第一行包含三个整数n, m, k 意义如题面所示
对于15% 的数据,1 n m 20, n m
对于40% 的数据,1 n 10, n m 1000
对于100% 的数据,1 n 100, n m 1018, 0 k n2
输出
输出包含1 个整数,代表LGTB 的方案数
样例
样例输入
5 6 1
样例输出
45

这道题…考试时想出了正解….好开心….然后…一个小地方忘了mod…结果….爆了…TAT我要哭死哭死哭死,…

下面来讲讲做法:
1.因为使n*n的涂色数一样,所以第1列与n+1列等效,2与n+2等效,同理一直等效下去。等效意义为涂色数相同。

2.由此易得方程f[i][j]=∑(q=1~min(n,j))f[i][j-q]*C(n,q)^h[i]
下面来解释一下这个方程:
f[i][j]表示前i列共涂了j个色块,而q则表示当前列要涂q个,所以有C(n,q)种涂法,而h[i]表示与当前列等效的个数,即m/n或m/n+1(i<=m%n)。表示的意思为:要涂q个,而与它等效的h[i]个同样每种都有C(n,q)种,故相乘。

3.C(n,q)^h[i]可以预处理,因为h[i]只有两种。
C(n,q)=(n-q+1)/k*C(n,q-1),这里在mod的时候要用到逆元,一个循环处理一下就ok,接下来就快速幂了。当然其他推方法也可以,我个人认为这种推的不容易错。

4.复杂度大概O(n^4),实际没有这么大,中间很多地方for不到√所以可以放心写,最慢的一组大概一秒多,还是蛮快啦。

代码:

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const int N=105,M=1e4+5,mod=1e9+7;
int n,k,w,nie[N];
LL f[2][M],c[M],r[2][M],m;
int ys;
void ksm(int i,int cc)
{
    LL d=c[i],ans=1;
    while(cc)
    {
        if(cc&1)ans=(ans*d)%mod;
        cc>>=1;d=(d*d)%mod;
    }
    r[0][i]=ans%mod; //C(n,i)^(m/n)
    r[1][i]=((LL)ans*(LL)c[i])%mod;//C(n,i)^(m/n+1)
}
void pre()
{
    ys=(LL)m%n;int c1=(LL)((LL)m/n)%(mod-1);
    c[0]=1;r[0][0]=r[1][0]=1;
    nie[1]=1;
    for(int i=2;i<=n;i++)
    nie[i]=(LL)((LL)(mod-mod/i)*(LL)nie[mod%i])%mod;//逆元
    for(int i=1;i<=n;i++)
    {
        c[i]=(c[i-1]*(LL)(n-i+1)%mod*(LL)nie[i])%mod;
        ksm(i,c1);
    }
}
void worrk()
{
    int pre=0,now=1;f[0][0]=f[1][0]=1;
    for(int i=1;i<=n;i++)
    {
        int yy=min(k,i*n),t=0;
        if(i<=ys)t=1;
        for(int j=0;j<=yy;j++)
        {
            f[now][j]=0;
            int y=min(j,n);
            for(int q=0;q<=y;q++)
            f[now][j]=(f[now][j]+((LL)f[pre][j-q]*(LL)r[t][q])%mod)%mod;
        }
        swap(now,pre);
    }
    cout<<f[pre][k]<<endl;
}
int main()
{
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);
    scanf("%d",&n);cin>>m;scanf("%d",&k);
    pre();
    worrk();
}

直接开数组是不会超的,习惯开滚动了。


T3

LGTB 与正方形
LGTB 最近迷上了正方形,现在他有n 个在二维平面上的点,请你告诉他在这些点中选4 个点能组成四条边
都平行于坐标轴的正方形的方案数有多少
输入
输入第一行包含一个整数n,代表点的数量
接下来n 行每行包含两个整数xi, yi,代表点的坐标
对于10% 的数据,1 n 50
对于30% 的数据,1 n 1000
对于100% 的数据,1 n 105,0 xi, yi 105
数据保证没有两点在同一位置
输出
输出包含一个整数代表方案数
样例
样例输入
5
0 0
0 2
2 0
2 2
1 1
样例输出
1
样例输入
9
0 0
1 1
2 2
0 1
1 0
0 2
2 0
1 2
2 1
样例输出
5

这道题先贴暴力代码吧,30分好像是。
排序查找。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e5+5;
int n,xi,yi,tx[N],ty[N];
LL ans;
struct node{
    int x,y,num;
};
node xx[N],yy[N];
bool comp1(const node&a,const node&b)
{
    if(a.x==b.x)return a.y<b.y;
    else return a.x<b.x;
}
bool comp2(const node&a,const node&b)
{
    if(a.y==b.y)return a.x<b.x;
    else return a.y<b.y;
}
LL pd(int x1,int x2)
{
    int cj=xx[x2].y-xx[x1].y;
    int xw1=xx[x1].x,xw2=xx[x2].x;
    int yw1=xx[x1].y,yw2=xx[x2].y;
    int y1=ty[xx[x1].num]+1,y2=ty[xx[x2].num]+1;
    LL t1=0,t2=0;
    while(yy[y1].y==yw1)
    {
        if(yy[y1].x-xw1==cj)t1++;
        y1++;
    }
    while(yy[y2].y==yw2)
    {
        if(yy[y2].x-xw2==cj)t2++;
        y2++;
    }
    return t1*t2;
}

void worrk()
{
    for(int i=1;i<n;i++)
    {
        int w=i+1;
        while(xx[w].x==xx[i].x)
        {
            ans+=pd(i,w);
            w++;
        }
    }
    cout<<ans<<endl;
}
int main()
{
    freopen("square.in","r",stdin);
    freopen("square.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&xi,&yi);
        xx[i].x=yy[i].x=xi;
        xx[i].y=yy[i].y=yi;
        xx[i].num=yy[i].num=i;
    }
    sort(xx+1,xx+n+1,comp1);
    sort(yy+1,yy+n+1,comp2);
    for(int i=1;i<=n;i++)
    {
        tx[xx[i].num]=i;
        ty[yy[i].num]=i;
    }
    worrk();
}

正解懒得写了…
贴上来自何神的解题报告:

迷之方法(很有道理)
将原坐标通过x分类,设每个分类为P[x]
如果P[x]中数的个数小于sqrt(n),直接暴力枚举里面元素(x相同,判断y获取正方形)
另外的P[x]暴力枚举这些集合,判断其中那些是y相等的
对于第一类小于sqrt(n)的点的集合,每个集合里面最多sqrt(n)个元素,所以该时间复杂度为O(n sqrt(n))
对于第二类,由于每一种size(P[x])>=sqrt(n),这种P[x]有最多sqrt(n)种,枚举这sqrt(n)种P[x],O(sqrt(n)^2) = O(n),枚举某一个集合中的所有元素,判断能否构成正方形就可以了该类O(n sqrt(n))
总时间复杂度O(n sqrt(n)) GGGG

迷之标程:

#include <set>
#include <cmath>
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <numeric>
#include <vector>
#include <ctime>
#include <queue>
#include <list>
#include <map>
#define pi acos(-1.0)
#define INF 0x3f3f3f3f
#define clr(x)  memset(x,0,sizeof(x));
#define clrto(x,siz,y)  for(int xx=0;xx<=siz;xx++)  x[xx]=y;
#define clrset(x,siz)  for(int xx=0;xx<=siz;xx++)  x[xx]=xx;
#define clr_1(x) memset(x,-1,sizeof(x));
#define clrmax(x) memset(x,0x3f,sizeof(x));
#define clrvec(x,siz) for(int xx=0;xx<=siz;xx++)  x[xx].clear();
#define fop2   freopen(".in","r",stdin); //freopen(".out","w",stdout);
#define fop   freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);
#define myprogram By_135678942570
#define clrcpy(x,siz,y)  for(int xx=0;xx<siz;xx++)  x[xx]=y[xx];
#define pb push_back
using namespace std;
struct point
{
    int x,y;
}P[100011];
int SIZ=400;
struct hash_map
{
    const static int mod=100007;
    int head[mod];
    struct hash_tables
    {
        long long key;
        int val;
        int next;
    }ele[100007];
    int N;
    int getHash(long long x)
    {
        return x%mod;
    }
    void init()
    {
        memset(head,255,sizeof(head));
        N=0;
    }
    int fint(long long x)
    {
        for(int i=head[getHash(x)];i!=-1;i=ele[i].next)
            if(ele[i].key==x)
                return i;
        return -1;
    }
    void insert(long long x)
    {
        int tmp=getHash(x);
        ele[N].key=x;
        ele[N].val=0;
        ele[N].next=head[tmp];
        head[tmp]=N++;
    }
    int& operator [](long long x)
    {
        int tmp=fint(x);
        if(tmp==-1)
        {
            insert(x);
            return ele[N-1].val;
        }
        else return ele[tmp].val;
    }
}HT;
vector<int>row[100111];
vector<int>GREAT;
vector<int>LESS;
int main()
{
    // fop;
    freopen("square.in", "r", stdin);
    freopen("square.out", "w", stdout);
    HT.init();
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&P[i].x,&P[i].y);
        row[P[i].x].pb(P[i].y);
        HT.insert(P[i].x*1000003ll+P[i].y);
    }
    for(int i=0;i<=100000;i++)
        if(row[i].size()>=SIZ)
            GREAT.pb(i);
        else if(row[i].size()>0)
            LESS.pb(i);
    int res=0;
    for(int i=0;i<LESS.size();i++)
    {
        int rowid=LESS[i];
        for(int j=0;j<row[rowid].size();j++)
            for(int k=j+1;k<row[rowid].size();k++)
            {
                int x1=rowid;
                int y1=row[rowid][j],y2=row[rowid][k];
                int x2=x1+abs(y1-y2);
                int x22=x1-abs(y1-y2);
                int f1=HT.fint(x2*1000003ll+y1);
                int f2=HT.fint(x2*1000003ll+y2);
                if(f1!=-1&&f2!=-1)
                {
                    res++;
                }
                if(x22>=0&&row[x22].size()>=SIZ)
                {
                    f1=HT.fint(x22*1000003ll+y1);
                    f2=HT.fint(x22*1000003ll+y2);
                    if(f1!=-1&&f2!=-1)
                        res++;
                }
            }
    }
    for(int i=0;i<GREAT.size();i++)
        sort(row[GREAT[i]].begin(),row[GREAT[i]].end());
    for(int i=0;i<GREAT.size();i++)
        for(int j=i+1;j<GREAT.size();j++)
        {
            int x1=GREAT[i];
            int x2=GREAT[j];
            int len=abs(x1-x2);
            int ii=0,jj=0;
            while(ii<row[x1].size()&&jj<row[x2].size())
            {
                if(row[x1][ii]==row[x2][jj])
                {
                    int f1=HT.fint(x1*1000003ll+row[x1][ii]+len);
                    int f2=HT.fint(x2*1000003ll+row[x2][jj]+len);
                    if(f1!=-1&&f2!=-1)
                        res++;
                    ii++,jj++;
                }
                else if(row[x1][ii]>row[x2][jj])
                    jj++;
                else ii++;
            }
        }
    printf("%d\n",res);
}

题外话:离noip还有两天!fighting!!
Do what I love.
Fight for what I want.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值