NOIP模拟题 2016.11.16 [模拟] [组合数递推] [数据分治] [Hash]

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


一开始以为是求最小长度GGG
当序列长度增加的时候,GCD的大小只会变得更小或者不变,那么要求最长的GCD为1(最小)的字串,就是全串。
Ans = GCD==1? N : -1
最短的二分加上线段树就好

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char)getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char)getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = (char)getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxn = 100005;
int n;
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    read(n);
    int GCD = 0;
    for(int i=1;i<=n;i++)
    {
        int tmp; read(tmp);
        GCD = gcd(GCD,tmp);
    }
    printf("%d",GCD==1?n:-1);
    return 0;
}

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
样例说明
样例如图所示,如果在灰色区域染一个格子,有20 种方案。如果在两边的白色格子各染一个格子,有25 种
方案。共45 种方案
31


当前n列有k个染色的时候,假设第1列有x个染色,那么第n+1列也应该有x个染色,后面的同理。
则kn+i列的染色个数与第i列染色个数相同
那么可以分成很多个列长度为n的块同时计算(最后一块小于等于n列)
用dp(i,j)表示处理了所有块的前i列,每一块总的染色个数为j的方案数
Dp(i,j) = ∑dp(i-1,j-p) * (C(n,p)) ^ T[i]
其中T[i]表示m列中共有多少个kn+i列
用快速幂预处理(C(n,p)) ^ T[i]
Dp用O(n^3)递推

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char)getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char)getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = (char)getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 105;
const int N = 100;
int quick_exp(int a,LL p)
{
    if(!p) return 1;
    int tmp = quick_exp(a,p>>1);
    tmp = (LL)tmp*tmp%mod;
    if(p&1) return (LL)tmp*a%mod;
    else return tmp;
}
int C[maxn][maxn];
void pre_work()
{
    C[0][0] = 1;
    for(int i=1;i<=N;i++)
        for(int j=0;j<=i;j++)
            C[i][j] = ( (j>=1?C[i-1][j-1]:0) + C[i-1][j] ) % mod;
}
int n,k;
LL m;
LL T[maxn];
int P[maxn][maxn]; // C(n,k)^T[i] for k and i
inline void init()
{
    read(n); read(m); read(k);
    for(int i=1;i<=n;i++) T[i] = (m-i)/n + 1;
    for(int p=0;p<=n;p++)
        for(int i=1;i<=n;i++)
            P[p][i] = quick_exp(C[n][p],T[i]);
}
int dp[maxn][maxn*maxn];
int dynamic()
{
    dp[0][0] = 1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=min(k,n*i);j++)
            for(int p=0;p<=min(n,j);p++)
                (dp[i][j] += (LL)dp[i-1][j-p]*P[p][i]%mod) %=mod;
    return dp[n][k];
}
int main()
{
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);
    pre_work();
    init();
    int ans = dynamic();
    printf("%d",ans);
    return 0;
}

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


迷之方法(很有道理)
将原坐标通过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))

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char)getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char)getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = (char)getchar();
    }
    x *= flag;
}
template <class T> T gcd(T a,T b) { return !b?a:gcd(b,a%b); }
const int INF=0x3f3f3f3f;
const int maxn = 100005;
const unsigned SIZE = 400u; // sqrt(n)
vector <int> P[maxn];
vector <int> GREAT,LESS;
int MINx,MAXx,MINy,MAXy;
inline bool inRange(int x,int y) { return MINx<=x&&x<=MAXx && MINy<=y&&y<=MAXy; }
struct HASH
{
    static const int mod = 120007;
    static const int maxhash = 130000;
    static const LL base = 1000009ll;
    struct Edge
    {
        int next;
        int x,y;
    }edge[maxhash];
    int head[maxhash];
    int maxedge;
    inline LL get_hash(int x,int y) { return (x*base+y) %mod; }
    inline void insert(int x,int y)
    {
        int _hash = (int)get_hash(x,y);
        edge[++maxedge] = (Edge) { head[_hash],x,y };
        head[_hash] = maxedge;
    }
    inline bool count(int x,int y)
    {
        if(!inRange(x,y)) return false;
        int _hash = (int)get_hash(x,y);
        for(int i=head[_hash];~i;i=edge[i].next)
            if(edge[i].x==x && edge[i].y==y) return true;
        return false;
    }
    HASH() { memset(head,-1,sizeof(head)); maxedge=-1; }
}Hash;
int n;
inline void init()
{
    MINx=MINy=INF;
    MAXx=MAXy=-INF;
    read(n);
    for(int i=1;i<=n;i++)
    {
        int x,y;
        read(x); read(y);
        if(!Hash.count(x,y)) Hash.insert(x,y),P[x].push_back(y);
        smin(MINx,x); smax(MAXx,x);
        smin(MINy,y); smax(MAXy,y);
    }
    for(int x=MINx;x<=MAXx;x++) if(P[x].size())
        if(P[x].size()>=SIZE) GREAT.push_back(x);
        else LESS.push_back(x);
    /*for(unsigned k=0;k<GREAT.size();k++)
        sort(P[GREAT[k]].begin(),P[GREAT[k]].end());*/
}
int work()
{
    int ans = 0;
    for(unsigned k=0;k<LESS.size();k++)
    {
        int x = LESS[k];
        for(unsigned i=0;i<P[x].size();i++)
            for(unsigned j=i+1;j<P[x].size();j++)
            {
                int len = abs(P[x][i]-P[x][j]);
                if(Hash.count(x-len,P[x][i]) && Hash.count(x-len,P[x][j])) ans++;
                if(x+len<=MAXx && P[x+len].size()>=SIZE && Hash.count(x+len,P[x][i]) && Hash.count(x+len,P[x][j])) ans++;
            }
    }
    for(unsigned i=0;i<GREAT.size();i++)
        for(unsigned j=i+1;j<GREAT.size();j++)
        {
            int x1 = GREAT[i];
            int x2 = GREAT[j];
            int len = abs(x1-x2);
            if(P[x1].size() < P[x2].size())
            {
                for(unsigned k=0;k<P[x1].size();k++)
                    if(Hash.count(x2,P[x1][k]) && Hash.count(x2,P[x1][k]+len) && Hash.count(x1,P[x1][k]+len)) ans++;
            }
            else
            {
                for(unsigned k=0;k<P[x2].size();k++)
                    if(Hash.count(x1,P[x2][k]) && Hash.count(x1,P[x2][k]+len) && Hash.count(x2,P[x2][k]+len)) ans++;
            }

        }
    return ans;
}
int main()
{
    freopen("square.in","r",stdin);
    freopen("square.out","w",stdout);
    init();
    int ans = work();
    printf("%d",ans);
    return 0;
}
原创文章 152 获赞 15 访问量 6万+

猜你喜欢

转载自blog.csdn.net/ourfutr2330/article/details/53190164
今日推荐