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.