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;
}