传送门:http://acm.hnu.cn/online/?action=problem&type=show&id=13348&courseid=320 Finding Lines |
Time Limit: 20000ms, Special Time Limit:50000ms, Memory Limit:65536KB |
Total submit users: 25, Accepted users: 11 |
Problem 13348 : No special judgement |
Problem description |
Annabel and Richard like to invent new games and play against each other. One day Annabel has a new game for Richard. In this game there is a game master and a player. The game master draws n points on a piece of paper. The task for the player is to find a straight line, such that at least p percent of the points lie exactly on that line. Richard and Annabel have very good tools for measurement and drawing. Therefore they can check whether a point lies exactly on a line or not. If the player can find such a line then the player wins. Otherwise the game master wins the game. |
Input |
The input consists of: |
Output |
Output one line containing either “possible” if it is possible to find a suitable line or “impossible” otherwise. |
Sample Input |
5 55 0 0 10 10 10 0 0 10 3 3 5 45 0 0 10 10 10 0 0 10 3 4 |
Sample Output |
possible impossible |
Judge Tips |
|
Problem Source |
NWERC 2014 |
/******************************************************************
* 给n(10w)点,画一条直线至少有ceil(n*p/100.)个点(20<=p<=100)
* ceil取上整,做法 从n个点钟随机选取两个点枚举其余点
* 手写随机比系统随机更有效,亲测!!!
******************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define LL long long
int x[100001],y[100001];
int n,p;
unsigned int suiji(){
//手写随机,42和22695477可以随机改,亲测39和246813579更快
static unsigned int seed=42;
return seed = 22695477*seed+1;
}
inline int online(int x1,int y1,int x2,int y2){
if((LL)(x1)*(LL)(y2)-(LL)(x2)*(LL)(y1)==0 )return 0;
return 1;
}
int main(){
while(~scanf("%d%d",&n,&p)){
for(int i=0;i<n;i++)
scanf("%d%d",&x[i],&y[i]);
if(n<=2){puts("possible");continue; }
bool flag=false;
int p1,p2,cnt;
for(int k=0;k<200;k++){
//while(p1=rand()%n,p2=rand()%n,p1==p2);
//系统随机函数,k达到500还wa
while(p1=suiji()%n,p2=suiji()%n,p1==p2);//200ac
cnt=2;
for(int i=0;i<n;i++){
if(p1==i||p2==i)continue;
if(online(x[p1]-x[i],y[p1]-y[i],x[p2]-x[i],y[p2]-y[i])==0)
cnt++;
if(100*cnt>=n*p){
flag=true;
break;
}
}
if(flag)break;
}
if(flag)puts("possible");
else puts("impossible");
}
return 0;
}
/************************************************************
* 随机姿势:随机1w次选取两点map保存斜率并统计
* 斜率次数>230 去暴力n个点
*************************************************************/
#include<iostream>
#include<cmath>
#include<cstdio>
#include<map>
using namespace std;
#define LL long long
LL x[100001],y[100001];
LL n,p;
LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
struct Line{
LL a,b,c;
Line(LL x1=0,LL y1=0,LL x2=0, LL y2=0){
LL d = gcd(abs(x1-x2), abs(y1-y2));
if (x1<x2) d = -d;
a = -(y1-y2)/d;
b = (x1-x2)/d;
c = a*x1 + b*y1;
}
bool operator < (const Line &L)const{
if(a!=L.a)return a<L.a;
if(b!=L.b)return b<L.b;
return c<L.c;//不能有等号<=
}
};
unsigned int suiji(){
static unsigned int seed = 42;
return seed = 22695477 * seed + 1;
}
map <Line,LL> mapt;
int main(){
while(~scanf("%64d%I64d",&n,&p)){
for(LL i=0;i<n;i++)scanf("%I64d%I64d",&x[i],&y[i]);
if(n<=2){puts("possible");continue;}
mapt.clear();
LL p1,p2,cnt;
for(LL k=0;k<10000;k++){
while(p1=suiji()%n,p2=suiji()%n,p1==p2);
mapt[Line(x[p1],y[p1],x[p2],y[p2])]++;
}
map<Line,LL>::iterator it;
LL a,b,c;
bool flag=false;
for(it=mapt.begin();it!=mapt.end();it++){
if(it->second > 230){
cnt=0;
a=it->first.a;
b=it->first.b;
c=it->first.c;
for(LL i=0;i<n;i++){
if(a*x[i]+b*y[i]==c)
cnt++;
if(100*cnt>=p*n){
flag=true;
break;
}
}
if(flag)break;
}
}
if(flag)puts("possible");else puts("impossible");
}
return 0;
}
#include<iostream>
#include<cmath>
#include<cstdio>
#include<set>
using namespace std;
#define LL long long
int x[100001],y[100001];
int gcd(int a,int b){return b==0?a:gcd(b,a%b); }
struct Line{
LL a,b,c;
Line(int x1=0,int y1=0,int x2=0,int y2=0){
int d=gcd(abs(x1-x2),abs(y1-y2));
if(x1<x2)d=-d;
a = -(y1-y2)/d;
b = (x1-x2)/d;
c = a*x1+b*y1;
}
bool operator < (const Line &L)const{
if(a!=L.a)return a<L.a;
if(b!=L.b)return b<L.b;
return c<L.c;
}
};
set<Line> findline(int l,int r,int p){
int m=(l+r)>>1;
set<Line>S,S1;
if(100>=p*(m-l+1)){//too little point
for(int i=l;i<=r;i++)
for(int j=i+1;j<=r;j++)
S1.insert(Line(x[i],y[i],x[j],y[j]));
}else{
S1 = findline(l,m,p);
set<Line> S2=findline(m+1,r,p);
S1.insert(S2.begin(),S2.end());
}
set<Line>::iterator it;
LL a,b,c;
int cnt;
for(it=S1.begin();it!=S1.end();it++){
a=it->a;
b=it->b;
c=it->c;
cnt=0;
for(int i=l;i<=r;i++)
if(a*x[i] + b*y[i] == c)
cnt++;
if(cnt*100 >= p*(r-l+1))
S.insert(*it);
}
return S;
}
int main(){
int n,p;
while(~scanf("%d%d",&n,&p)){
for(int i=0;i<n;i++)scanf("%d%d",&x[i],&y[i]);
if(n<=2||findline(0,n-1,p).size())puts("possible");
else puts("impossible");
}
return 0;
}