URAL 1317
/*
A题题意:一个用高度为h的围栏围住的停车场里面有一个激光发射器,它可以消灭距离在R之内的冰雹(冰雹不能落到比围栏低的位置或者被围栏挡住),求可以消灭的冰雹的数量
解法:先确定冰雹与凸包的位置关系,然后分类讨论(1)冰雹落点在凸包里面,直接计算最小距离是否大于R(2)冰雹落点在凸包外面,当冰雹恰好未被围栏挡住时距离最小,求出冰雹与发射器连线与围栏在平面上的交点,再利用相似三角形求出最小距离与R比较
注意线段与线段求交。。。
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const double PI = acos(-1.0);
const double eps = 1e-10;
const double INF = 1e5;
int dcmp(double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; }
// Point Vector
struct Point {
double x, y;
Point() { }
Point(double x, double y) : x(x), y(y) { }
bool operator < (const Point &A) const {
return dcmp(x-A.x) < 0 || (dcmp(x-A.x) == 0 && dcmp(y-A.y) < 0);
}
void read(){
double x,y; scanf("%lf%lf",&x,&y);
this->x=x, this->y=y;
}
};
typedef Point Angle;
typedef Point Vector;
Point operator + (const Point &A, const Point &B) { return Point(A.x+B.x, A.y+B.y); }
Point operator - (const Point &A, const Point &B) { return Point(A.x-B.x, A.y-B.y); }
Point operator * (const Point &A, double b) { return Point(A.x*b, A.y*b); }
Point operator / (const Point &A, double b) { return Point(A.x/b, A.y/b); }
bool operator == (const Point &A, const Point &B) { return dcmp(A.x-B.x) == 0 && dcmp(A.y-B.y) == 0; }
double Dot(const Point &A, const Point &B) { return A.x*B.x + A.y*B.y; }
double Cross(const Point &A, const Point &B) { return A.x*B.y - A.y*B.x; }
double Length(const Point &A) { return sqrt(Dot(A, A)); }
double Area2(const Point &A, const Point &B, const Point &C) { return Cross(B-A, C-A); }
Point Rotate(const Point &A, double ang) {
return Point(cos(ang)*A.x - sin(ang)*A.y, sin(ang)*A.x + cos(ang)*A.y);
}
Point Normal(const Point &A) {
double L = Length(A); return Point(-A.y/L, A.x/L);
}
// Line Segment
struct Line {
Point A, B, v;
double ang;
Line() { }
Line(Point A, Point B): A(A), B(B) { v = B-A; ang = atan2(v.y, v.x); }
// ax + by + c > 0
Line(double a, double b, double c) {
v = Point(b, -a);
if (fabs(a) > fabs(b)) A = Point(-c/a, 0); else A = Point(0, -c/b);
B = A + v;
ang = atan2(v.y, v.x);
}
bool operator < (const Line &A) const { return ang < A.ang; }
Point point(double t) const { return A + v*t; }
};
int LineLineIntersection(const Line& L1, const Line& L2, Point* p, double* t=0) {
if(dcmp(Cross(L1.v,L2.v))==0)
return dcmp(Cross(L1.v,L2.A-L1.A))==0 ? -1 : 1;
p[0]=L1.point(Cross(L2.v, L1.A-L2.A) / Cross(L1.v, L2.v));
if(t) t[0]=Cross(L2.v, L1.A-L2.A) / Cross(L1.v, L2.v);
return 1;
}
double DistanceToLine(const Point &P, const Line &L) {
return fabs(Cross(L.v, P-L.A)) / Length(L.v);
}
Point GetLineProjection(const Point &P, const Line &L) {
return L.point(Dot(P-L.A, L.v) / Dot(L.v, L.v));
}
int Position(const Point &P, const Line &L) { return dcmp(Cross(L.v, P-L.A)); }
double DistanceToSegment(const Point &P, const Line &L) {
if (dcmp(Dot(L.v, P-L.A)) < 0) return Length(P-L.A);
else if (dcmp(Dot(L.v, P-L.B) > 0)) return Length(P-L.B);
else return DistanceToLine(P, L);
}
bool SegmentProperIntersection(const Line &L1, const Line &L2) {
int c1 = Position(L2.A, L1), c2 = Position(L2.B, L1),
c3 = Position(L1.A, L2), c4 = Position(L1.B, L2);
return c1*c2 < 0 && c3*c4 < 0;
}
bool OnSegment(const Point &P, const Line &L) {
return dcmp(Cross(L.A-P, L.B-P)) == 0 &&
dcmp(Dot(L.A-P, L.B-P)) <= 0;
}
bool OnSegment2(const Point &P, const Line &L) {
return dcmp(L.A.x - P.x) * dcmp(L.B.x - P.x) <= 0 && dcmp(L.A.y - P.y) * dcmp(L.B.y - P.y) <= 0;
}
// Polygon
typedef vector<Point> Polygon;
typedef std::vector<Line> Lines;
void print(const Polygon& A) {
for (int i = 0; i < A.size(); ++ i) printf("%.2lf %.2lf\n", A[i].x, A[i].y);
}
double PolygonArea(const Polygon &p) {
int n = p.size();
double area = 0;
for (int i = 1; i < n-1; ++ i)
area += Area2(p[0], p[i], p[i+1]);
return area / 2.0;
}
int isPointInPolygon(const Point &P, const Polygon &p) {
int n = p.size();
int wn = 0;
for (int i = 0; i < n; ++ i) {
const Point &p1 = p[i]; const Point &p2 = p[(i+1)%n];
if (P == p1 || P == p2 || OnSegment(P, Line(p1, p2))) return -1;
int k = dcmp(Cross(p2-p1, P-p1));
int d1 = dcmp(p1.y-P.y);
int d2 = dcmp(p2.y-P.y);
if (k > 0 && d1 <= 0 && d2 > 0) ++ wn;
if (k < 0 && d2 <= 0 && d1 > 0) -- wn;
}
return wn != 0;
}
// ConvexHull
Polygon ConvexHull(Polygon p) {
int n = p.size();
sort(p.begin(), p.end());
// int n = p.erase(std::unique(p.begin(), p.end()), p.end());
Polygon q(n+1);
int m = 0;
for (int i = 0; i < n; ++ i) {
while (m > 1 && Cross(q[m-1]-q[m-2], p[i]-q[m-2]) <= 0) -- m;
q[m ++] = p[i];
}
int k = m;
for (int i = n-2; i >= 0; -- i) {
while (m > k && Cross(q[m-1]-q[m-2], p[i]-q[m-2]) <= 0) -- m;
q[m ++] = p[i];
}
if (n > 1) m --;
q.resize(m);
return q;
}
int n,m;
Polygon A;
double H, D;
Point las, stone;
double sqr(double x){return x*x;}
void solve(){
scanf("%d",&n); A.resize(n);
scanf("%lf",&H);
for(int i=0;i<n;++i) A[i].read();
scanf("%lf",&D); las.read();
scanf("%d",&m);
int res=0;
while(m--){
stone.read();
if(isPointInPolygon(stone,A)){
++res;
}else{
Line L=Line(las,stone);
Point p; double t;
for(int i=0;i<n;++i){
Line Lx=Line(A[i],A[(i+1)%n]);
if(LineLineIntersection(L,Lx,&p,&t)==1&&OnSegment(p,Lx)&&dcmp(t)>=0)break;
}
double d=Length(L.v)/Length(p-las)*sqrt(sqr(Length(p-las))+sqr(H));
if(dcmp(d-D)<=0) ++ res;
}
}
printf("%d\n",res);
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}
URAL 1318
/*
题意:看公式。。。
题解:
10^0~10^38打个表出来
然后二分每个数在哪两个之间
坑点:注意不要越界qwq,打到39的时候,答案还比38大=-=,天真的以为没越界。。。
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXLOG=39;
struct bign{
unsigned a[4];
bign(){ memset(a,0,sizeof a); }
bool operator<(const bign& B)const{
for(int i=3;i>=0;--i)if(a[i]!=B.a[i]) return a[i]<B.a[i];
return 0;
}
} num[MAXLOG];
bign operator*(const bign& A,int b){
bign C;
LL p=0;
for(int i=0;i<4;++i){
p = (p >> 32) + ((LL)A.a[i]*b);
C.a[i] = (p&(0xffffffff));
}
return C;
}
bign operator^(const bign& A,const bign& B){
bign C;
for(int i=0;i<4;++i){
C.a[i]=A.a[i]^B.a[i];
}
return C;
}
const int maxn=5010;
bign A[maxn];
int n;
void solve(){
scanf("%d",&n);
for(int i=0;i<n;++i) for(int j=3;j>=0;--j) scanf("%u",&A[i].a[j]);
int res=0;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j){
int x=upper_bound(num,num+MAXLOG,A[i]^A[j])-num-1;
res += max(x,0);
}
printf("%d\n",res);
}
int main(){
// freopen("in.txt","r",stdin);
num[0].a[0]=1;
for(int i=1;i<MAXLOG;++i)
num[i]=num[i-1]*10;
solve();
// for(;;);
return 0;
}
URAL 1319
/*
C题题意是在n*n的矩阵里填数,从右上角开始填。每次向右下角填。
模拟
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
const int maxn=110;
int a[maxn][maxn];
int n;
void solve(){
scanf("%d",&n);
int no=0;
{
int i=1;
for(int j=n;j>=1;--j)
for(int k=0;j+k<=n;++k)
a[i+k][j+k]=++no;
}
{
int j=1;
for(int i=2;i<=n;++i)
for(int k=0;i+k<=n;++k)
a[i+k][j+k]=++no;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
printf("%d%c", a[i][j], j==n?'\n':' ');
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}
URAL 1320
/*
题意:给一张图,问是否可以用若干个“相邻边对”来划分整个图。。“相邻边对”定义为两条边有公共点。。
题解:每个联通块边数为偶数,答案为T,否则False
(怎么证。。。)
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
const int maxn=1010;
int pa[maxn];
int findset(int x){ return pa[x]==x ? x : pa[x]=findset(pa[x]); }
int sz[maxn];
int deg[maxn];
void solve(){
for(int i=1;i<maxn;++i)pa[i]=i;
int u,v;
while(scanf("%d%d",&u,&v)==2){
++deg[u],++deg[v];
int p=findset(u),q=findset(v);
if(p!=q) pa[p]=q, sz[q]=sz[q]+sz[p]+1;
else sz[p]++;
}
int fg=1;
for(int i=1;i<=1000;++i){
int p=findset(i);
if(sz[p]&1){ fg=0; break; }
}
puts(fg ? "1" : "0");
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}
URAL 1321
/*
题意:电梯显示屏有故障,显示数字每一位有7个显像管,然后问最少坐几层楼能排查出所有故障的显像管。(故障可能是始终亮或始终暗)
例如,10层楼,至少需要2-10共8层楼,才能排除所有故障。
注意:显示不含前导0,并且用不到的显像管不需要排查。
题目保证层数>4
题解:
分类讨论:
如果只有一位,因为题目保证层数>4,所以每根显像管都用上了,所以一定要是[1,5]共4层。
如果第一位是[4,9],那么第一位所有显像管都必须排查,故一定是[19999...,40000...]共30000...01层
如果第一位是[2,3],那么除了左上角那一位其余所有都必须排查,故一定是[09999...,20000...]共10000...01层
如果第一位是1,那么注意:此时的第二位始终会显示0,而10个数字中,右下角的显像管必须有2才能排查,故
如果第二位是[2,9],那么就是[069999...,120000...],共050000...01层
如果第二位是[0,1],那么就是[029999...,10000...],共070000...01层
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
const int maxn=1010;
char num[maxn];
int n;
void solve(){
scanf("%s",num); n=strlen(num);
if(n==1){
puts("4"); return;
}
if(num[0]>='4'){
for(int i=0;i<n;++i){
if(i==0)putchar('3');
else if(i==n-1)putchar('1');
else putchar('0');
}
return;
}
if(num[0]>='2'){
for(int i=0;i<n;++i){
if(i==0)putchar('1');
else if(i==n-1)putchar('1');
else putchar('0');
}
return;
}
//num[0]=='1'
if(num[1]>='2'){
if(n==2){ putchar('6'); return; }
for(int i=1;i<n;++i){
if(i==1)putchar('5');
else if(i==n-1)putchar('1');
else putchar('0');
}
return;
}
//num[1]>='0'
{
if(n==2){ putchar('8'); return; }
for(int i=1;i<n;++i){
if(i==1)putchar('7');
else if(i==n-1)putchar('1');
else putchar('0');
}
return;
}
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}
URAL 1322
/*
题意:一个字符串的所有循环同构按照字典序排序。按顺序给出每种同构的最后一位,求第k小的同构。n <= 10^5
题解:
他给出的那个串一定包括了这个串的所有字母。那么第一位一定是按照大小把他们摆放好。然后就确定了每个字母后面是哪个字母,然后一直找下去就能把这个串构造出来
把他们按照给出的顺序编号,那么我们可以确定每号字母后面的字母是第几号。那么从第k号开始连续找n个就行
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<functional>
using namespace std;
const int maxsigma=53;
int idx(char x){ return 'A'<=x&&x<='Z' ? x-'A' : (x=='_' ? x-'_'+26 : x-'a'+27); }
const int maxn=100010;
int m;
char s[maxn],t[maxn]; int n;
vector<int> nxt[maxsigma];
int no[maxsigma+10];
int go[maxn];
void solve(){
scanf("%d",&m);
scanf("%s",s);n=strlen(s);
memcpy(t,s,sizeof s); sort(t,t+n);
memset(no,0,sizeof no);
for(int i=0;i<n;++i)
++no[idx(s[i])+1];
for(int i=1;i<=maxsigma;++i) no[i]+=no[i-1];
for(int i=0;i<n;++i)
go[no[idx(s[i])]++]=i;
int p=m-1;
for(int i=0;i<n;++i){
putchar(t[p]);
p=go[p];
}
putchar('\n');
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}
URAL 1323
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
const int maxn=11;
int f[1<<maxn][1<<maxn]; P g[1<<maxn][1<<maxn];
int upd(int& a,int b){ return a>b ? a=b,1 : 0; }
int n,m;
P Q[500000]; int l,r;
int G[maxn][maxn];
char s1[30],s2[30];
int lg2[1<<maxn];
map<string, int> idx;
string iidx[maxn];
int idxN;
int index(string s){
if(!idx.count(s)){ idx[s]=idxN; iidx[idxN]=s; ++ idxN; return idxN-1; }
return idx[s];
}
vector<P> ans[maxn];
void print(int x,int y,int lx,int ly){
if(g[x][y].first) print(g[x][y].first,g[x][y].second,x,y);
if(f[lx][ly]>f[x][y]) return;
if(lx!=-1){
ans[f[x][y]].push_back(P(lg2[y^ly],lg2[x^lx]));
// printf("%s %s\n",iidx[lg2[y^ly]].c_str(),iidx[lg2[x^lx]].c_str());
}
}
void solve(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;++i){
scanf("%s%s",s1,s2);
int n1=index(s1),n2=index(s2);
G[n1][n2]=G[n2][n1]=1;
}
memset(f,0x3f,sizeof f);
scanf("%s",s1);
int s=index(s1);
f[1<<s][0]=0;
l=r=0; Q[r++]=P(1<<s,0);
for(;l!=r;++l){
int x=Q[l].first,y=Q[l].second;
int d=f[x][y];
for(int i=0;i<n;++i)if((y>>i)&1){
for(int j=0;j<n;++j)if(G[i][j]&&!((x>>j)&1)){
if(upd(f[x|(1<<j)][y&~(1<<i)],d)){ // 选一个这一轮的人,再选一个点拓展
Q[r++]=P(x|(1<<j),y&~(1<<i));
g[x|(1<<j)][y&~(1<<i)]=Q[l];
}
}
}
if(upd(f[x][x],d+1)){ // 更新一轮
Q[r++]=P(x,x);
g[x][x]=Q[l];
}
}
int mnf=INF; P mni;
for(int i=0;i<(1<<n);++i)if(upd(mnf,f[(1<<n)-1][i]))
mni=P((1<<n)-1,i);
printf("%d\n",mnf);
print(mni.first,mni.second,-1,-1);
for(int i=1;i<=mnf;++i){
printf("%d\n",ans[i].size());
for(int j=0;j<ans[i].size();++j)printf("%s %s\n",iidx[ans[i][j].first].c_str(),iidx[ans[i][j].second].c_str());
}
}
int main(){
// freopen("in.txt","r",stdin);
lg2[0]=-1; for(int i=1;i<(1<<maxn);++i)lg2[i]=lg2[i-1]+!(i&(i-1));
solve();
// for(;;);
return 0;
}
URAL 1324
URAL 1325
URAL 1326
/*
J题题意,有n件物品各自有价格,还有m种打包购买的方案,现在要买其中的若干件,求最小代价
解法:状压,f[i]表示已购买物品情况为i时的最小价值,方程f[i | w[j]] = min(f[i | w[j]], f[i] + p[j]),w[j]为第j种买法的状压,p[j]为价格
注意:同一件物品可以买多次;可以买额外的物品
其中转移可以看成图的转移,然后变为求最短路,坑点在于:最后答案是多个取min(因为可以买额外的。。)
*/
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
typedef pair<int,int> P;
const int maxn=30;
const int MAXN=1<<21;
const int maxm=2010;
int n,m;
int A[maxn];
P B[maxm];
int dis[MAXN], inq[MAXN];
void spfa(int s) {
static deque<int> deq;
memset(dis, 0x3f, sizeof dis);
memset(inq, 0, sizeof inq);
dis[s] = 0; deq.push_back(s); inq[s] = 1;
while (!deq.empty()) {
int u = deq.front(); deq.pop_front(); inq[u] = 0;
for(int i=0;i<m;++i){
int v=u|B[i].first, w=B[i].second;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!inq[v]) {
deq.empty() || dis[v] < dis[deq.front()] ?
deq.push_front(v) : deq.push_back(v);
inq[v] = 1;
}
}
}
}
}
void solve(){
scanf("%d",&n);
for(int i=0;i<n;++i)scanf("%d",&A[i]);
scanf("%d",&m);
for(int i=0;i<m;++i){
int v,y;scanf("%d%d",&v,&y);
int S=0;
while(y--){
int x;scanf("%d",&x); -- x;
S|=1<<x;
}
B[i]=P(S,v);
}
for(int i=0;i<n;++i) B[m++]=P(1<<i,A[i]);
spfa(0);
int T=0;
{
int y;scanf("%d",&y);
while(y--){
int x;scanf("%d",&x); -- x;
T|=1<<x;
}
}
int res=0x3f3f3f3f;
for(int S=0;S<(1<<n);++S)if((S&T)==T) res=min(res,dis[S]);
printf("%d\n",res);
}
int main(){
// freopen("in.txt","r",stdin);
solve();
// for(;;);
return 0;
}