【前言】
在BZOJ上翻题看到了几题,心血来潮就全写了。
C这个搜索我不是很会写,直接看了别人的(然而还是没写)
然后这个J让我知道一定不能在还要用值的时候删掉一个指针。
【题目】
原题地址
A.Ascending Photo
单独写。
B.Boss Battle
显然每次可以缩减一个可能的位置,所以若 n ≤ 3 n\leq 3 n≤3则答案为 1 1 1,否则答案就是 n − 2 n-2 n−2。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
#endif
int n=read();
if(n<=3) puts("1");
else printf("%d\n",n-2);
return 0;
}
C.Connect the Dots
考虑任意一条线段一定满足:斜率为2个不超过20的整数的比值且至少经过1个点。
搜索状态为(当前画到了第几个点,当前所在射线的方向)
转移为: 在这个点转一下方向。 直接画到下一个点。画到下一个点,中间转一次方向。
显然不是我的代码
#include<bits/stdc++.h>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int>
#define pi pair<int,int>
#define SI(a) ((a).size())
#define ALL(x) (x).begin(),(x).end()
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
ll sqr(ll a){return a*a;}
ld sqr(ld a){return a*a;}
double sqr(double a){return a*a;}
const double eps=1e-10;
int dcmp(double x) {
if (fabs(x)<eps) return 0; else return x<0 ? -1 : 1;
}
ld PI = 3.141592653589793238462643383;
class P{
public:
ll x,y;
P(ll x=0,ll y=0):x(x),y(y){}
friend ll Dot(P A,P B) {return A.x*B.x+A.y*B.y; }
friend P operator- (P A,P B) { return P(A.x-B.x,A.y-B.y); }
friend P operator+ (P A,P B) { return P(A.x+B.x,A.y+B.y); }
friend P operator* (P A,double p) { return P(A.x*p,A.y*p); }
friend P operator/ (P A,double p) { return P(A.x/p,A.y/p); }
friend bool operator< (const P& a,const P& b) {return dcmp(a.x-b.x)<0 ||(dcmp(a.x-b.x)==0&& dcmp(a.y-b.y)<0 );}
P operator-()const {return P(-x,-y);}
};
P read_point() {
P a;
scanf("%lld%lld",&a.x,&a.y);
return a;
}
bool operator==(const P& a,const P& b) {
return a.x==b.x&&a.y==b.y;
}
bool operator!=(const P& a,const P& b) {
return a.x!=b.x||a.y!=b.y;
}
typedef P V;
ll Cross(V A,V B) {return A.x*B.y - A.y*B.x;}
int n=4,a[1000][100];
P p[1000];
bool OnRay(P a,V v,P b){
return (dcmp(Cross(b-a,v))==0 && dcmp(Dot(b-a,v))>=0) ;
}
double x_max=10000;
P c;
bool RayIntesection(P a,V v,P b,V w){
int det=Cross(v,w);
if(dcmp(det)==0) {
if (!OnRay(a,v,b) && !OnRay(b,w,a)) return false;
} else {
int s = Cross(b-a,w), t = Cross(b-a,v);
if (s*det < 0 || t*det < 0) return false;
double ss = double(s)/det;
double cx = a.x+ss*v.x,cy = a.y+ss*v.y;
if (abs(cx) > x_max || abs(cy) > x_max) return false;
}
return true;
}
typedef pair<int,P> state;
int dist[100][100][100];
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
memset(dist,0x3f3f3f3f,sizeof(dist));
For(i,4) {
For(j,4) {
a[i][j]=read();
p[a[i][j]-1]=P(j,-i+5);
}
}
vector<P> vs;
Fork(x,-30,30) Fork(y,-30,30) if(abs(__gcd(x,y))==1) {
vs.pb(P(x,y));
}
deque<state> q;
for(auto v:vs) {
dist[v.x+50][v.y+50][0] = 1;
q.emplace_back(0,v);
}
auto relax = [&] (state s,state t,int len){
if(dist[t.se.x+50][t.se.y+50][t.fi]>dist[s.se.x+50][s.se.y+50][s.fi]+len) {
dist[t.se.x+50][t.se.y+50][t.fi]=dist[s.se.x+50][s.se.y+50][s.fi]+len;
if(!len) q.push_front(t);
else q.push_back(t);
}
};
int ans=1e9+7;
int an[16];
Rep(i,16) an[i]=INF;
while(!q.empty()){
int i; P v;
tie(i,v) = q.front();
q.pop_front();
an[i]=min(an[i],dist[v.x+50][v.y+50][i]);
if (i==15) {
ans=min(ans,dist[v.x+50][v.y+50][i]) ;
continue;
}
for(auto w:vs) {
if (v!=w) {
relax({i,v},{i,w},1); //正好在点i改变方向
}
}
if(OnRay(p[i],v,p[i+1])) {
relax({i,v},{i+1,v},0); //不改变方向
// cerr<<i<<' '<<dist[v.x+50][v.y+50][i+1]<<endl;
}
for(auto w:vs) {
if (v!=w) {
if (!RayIntesection(p[i],v,p[i+1],-w)) continue;
relax({i,v},{i+1,w},1); //在i点延长出去某点改变方向
}
}
}
// Rep(i,16) cerr<<an[i]<<' ';puts("");
cout<<ans<<endl;
return 0;
}
D.Dunglish
按题意模拟,用乘法原理计算即可。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n,m;
string s[25],st1,st2,st3;
ll ans1,sum;
map<string,pii>mp;
map<string,string>mp2;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) cin>>s[i];
m=read();
for(int i=1;i<=m;++i)
{
cin>>st1>>st2>>st3;
if(!mp.count(st1)) mp[st1]=mkp(0,0);
mp2[st1]=st2;
if(st3[0]=='c') ++mp[st1].fi;
else ++mp[st1].se;
}
sum=ans1=1;
for(int i=1;i<=n;++i)
{
pii t=mp[s[i]];
//cerr<<s[i]<<" "<<t.fi<<" "<<t.se<<endl;
sum=sum*(t.fi+t.se);ans1=ans1*t.fi;
}
if(sum>1) printf("%lld correct\n%lld incorrect\n",ans1,sum-ans1);
else
{
for(int i=1;i<=n;++i) cout<<mp2[s[i]]<<" ";
puts("");
puts(ans1?"correct":"incorrect");
}
return 0;
}
E.English Restaurant
F.Factor-Free Tree
限制条件等价于每个点和其子树内点互质,则中序遍历上往前后若干个互质。
于是我们分解质因数后维护每个质因子最后出现的位置,就可以求出第
i
i
i个往前后多少范围内互质。
接下来考虑暴力的做法,实际上我们需要每次提出根节点然后递归往下处理。于是这相当于一个分治的逆过程,我们维护左右两个指针,同时往中间扫,可以保证复杂度。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e6+10,M=1e7+10;
int n,pnum;
int bo[M],fr[M],pri[N];
int fa[N],a[N],L[N],R[N],b[M];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
void initpri()
{
for(int i=2;i<M;++i)
{
if(!bo[i]) pri[++pnum]=i,fr[i]=i;
for(int j=1;j<=pnum && (ll)pri[j]*i<M;++j)
{
bo[i*pri[j]]=1,fr[i*pri[j]]=pri[j];
if(!(i%pri[j])) break;
}
}
}
bool solve(int l,int r,int f)
{
if(l>r) return 1;
int le=l,ri=r;
while(le<=ri)
{
if(L[le]<l && R[le]>r)
{
fa[le]=f;
return (solve(l,le-1,le) && solve(le+1,r,le));
}
if(L[ri]<l && R[ri]>r)
{
fa[ri]=f;
return (solve(l,ri-1,ri) && solve(ri+1,r,ri));
}
++le;--ri;
}
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("F.in","r",stdin);
freopen("F.out","w",stdout);
#endif
initpri();
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i)
{
int now=a[i],las=0;
while(now^1)
{
int tmp=fr[now];las=max(las,b[tmp]);
b[tmp]=i;while(!(now%tmp))now/=tmp;
}
L[i]=las;
}
for(int i=1;i<M;++i) b[i]=n+1;
for(int i=n;i;--i)
{
int now=a[i],las=n+1;
while(now^1)
{
int tmp=fr[now];las=min(las,b[tmp]);
b[tmp]=i;while(!(now%tmp))now/=tmp;
}
R[i]=las;
}
if(solve(1,n,0)) for(int i=1;i<=n;++i) printf("%d ",fa[i]);
else puts("impossible");
return 0;
}
G.Glyph Recognition
枚举多少边形,然后二分出多边形外接圆半径(也就是原点到顶点距离)。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
const db eps=1e-7,PI=acos(-1);
const int N=1005;
int n;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
struct point
{
db x,y;
point(db _x=0,db _y=0):x(_x),y(_y){}
}pt[N],p[10];
struct vec
{
point p;db x,y;
void in(point p1,point p2){p=p1;x=p2.x-p1.x;y=p2.y-p1.y;}
vec(){}
vec(db _x,db _y):x(_x),y(_y){}
}v[10];
db cross(vec a,vec b){return a.x*b.y-a.y*b.x;}
int check(int k,db r)
{
int res=0;
for(int i=1;i<=k;++i) p[i]=point(r*cos((i-1)*2*PI/k),r*sin((i-1)*2*PI/k));
for(int i=1;i<k;++i) v[i].in(p[i],p[i+1]);
v[k].in(p[k],p[1]);
for(int i=1,j=1;i<=n;++i)
{
for(j=1;j<=k;++j)
if(cross(vec(pt[i].x-v[j].p.x,pt[i].y-v[j].p.y),v[j])>eps) break;
if(j>k) ++res;
}
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("G.in","r",stdin);
freopen("G.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) pt[i].x=read(),pt[i].y=read();
db ans=-1;int ansk;
for(int k=3;k<=8;++k)
{
db l=eps,r=1e9,r1,r2;
while(l+eps<r)
{
db mid=(l+r)/2.0;
if(check(k,mid)==n) r=mid;
else l=mid;
}
r1=l;l=eps;r=1e9;
while(l+eps<r)
{
db mid=(l+r)/2.0;
if(check(k,mid)) r=mid;
else l=mid;
}
r2=l;
if(r2/r1>ans+eps) ans=r2/r1,ansk=k;
}
printf("%d %.10lf\n",ansk,ans*ans);
return 0;
}
H.High Score
因为平方增长较快,所以全部给某个数是最优的,但在小数据下不一定成立,故小数据暴力枚举即可。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll ans,a,b,c,d;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
ll sqr(ll x){return x*x;}
ll calc(ll x,ll y,ll z){return sqr(x)+sqr(y)+sqr(z)+min(min(x,y),z)*7;}
void solve1()
{
for(int i=0;i<=d;++i) for(int j=0;j<=d;++j) for(int k=0;k<=d;++k)
if(i+j+k==d) ans=max(ans,calc(a+i,b+j,c+k));
}
void solve2()
{
ans=max(ans,calc(a+d,b,c));
ans=max(ans,calc(a,b+d,c));
ans=max(ans,calc(a,b,c+d));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("H.in","r",stdin);
freopen("H.out","w",stdout);
#endif
int T=read();
while(T--)
{
a=read(),b=read(),c=read(),d=read();ans=0;
if(d<=10) solve1();
else solve2();
printf("%lld\n",ans);
}
return 0;
}
I.Installing Apps
每个应用可以看作先占用 max ( a i , b i ) \max(a_i,b_i) max(ai,bi)的空间再释放 max ( a i , b i ) − b i \max(a_i,b_i)-b_i max(ai,bi)−bi的空间。假设全部都要安装,那么按释放空间从大到小安装最优。于是我们这样排序后设 f i , j f_{i,j} fi,j表示前 i i i个应用,剩余空间 j j j时最多安装多少个应用即可。
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=505,M=10005;
int n,C;
int f[N][M],g[N][M],w[N][M];
vector<int>q;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
struct node{int p,w,st;}a[N];
bool cmp(node &a,node &b){return a.st>b.st;}
void gmax(int &x,int y){if(y>x)x=y;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("I.in","r",stdin);
freopen("I.out","w",stdout);
#endif
n=read();C=read();
for(int i=1;i<=n;++i)
{
int d=read(),s=read();
a[i].p=i,a[i].w=max(d,s),a[i].st=a[i].w-s;
}
sort(a+1,a+n+1,cmp);
memset(f,-0x3f,sizeof(f));f[0][C]=0;
for(int i=1;i<=n;++i)
{
for(int j=0;j<=C;++j)
{
f[i][j]=f[i-1][j];g[i][j]=j;w[i][j]=0;
}
for(int j=0;j<=C;++j) if(f[i-1][j]>=0)
{
if(j<a[i].w) continue;
int t=j-a[i].w+a[i].st;
if(f[i-1][j]+1>f[i][t])
{
f[i][t]=f[i-1][j]+1;
g[i][t]=j;w[i][t]=a[i].p;
}
}
}
int h=0;
for(int i=0;i<=C;++i) if(f[n][i]>f[n][h]) h=i;
printf("%d\n",f[n][h]);
for(int i=n;i;h=g[i][h],--i) if(w[i][h]) q.pb(w[i][h]);
for(int i=(int)q.size()-1;~i;--i) printf("%d ",q[i]);
return 0;
}
J.Juggling Troupe
最终状态只有 0 , 1 0,1 0,1,而观察到一个单独的 2 2 2一定会分到左右两边第一个 0 0 0的位置,设为 l , r l,r l,r。那么 l , r l,r l,r会变为 1 1 1,且 l + r − i l+r-i l+r−i的位置会变成 0 0 0。于是用 set \text{set} set维护 0 0 0的位置,然后扫过去即可。复杂度 O ( n log n ) O(n\log n) O(nlogn)
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e6+10;
int n;
char a[N];
set<int>st;
set<int>::iterator l,r;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("J.in","r",stdin);
freopen("J.out","w",stdout);
#endif
scanf("%s",a+1);n=strlen(a+1);
for(int i=1;i<=n;++i) if(a[i]=='0') st.insert(i);
st.insert(0);st.insert(n+1);
for(int i=1;i<=n;++i)
{
if(a[i]!='2') continue;
r=st.lower_bound(i);l=r;l--;
//cerr<<*l<<" "<<*r<<endl;
int x=*l+*r-i;//we must remember the point
if(*l>0) st.erase(l);
if(*r<=n) st.erase(r);
st.insert(x);
}
for(int i=1;i<=n;++i) a[i]='1';
for(l=st.begin();l!=st.end();++l) a[*l]='0';
for(int i=1;i<=n;++i) putchar(a[i]);
return 0;
}
K.Knockout Tournament
对于
1
1
1,要让他的对手尽量弱小,而对于其他人,要让他的对手和他水平尽量接近,以降低他的胜率。
故将
1
1
1看作
0
0
0水平后从小到大排序,相邻的配对即可。然后计算概率的时候只需要暴力枚举两边的胜者,两个点只会在
l
c
a
lca
lca处被计算,复杂度为
O
(
n
2
)
O(n^2)
O(n2)
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<int,db> pid;
const int N=8200;
int n,m,cnt,a[N],id[N];
vector<pid>f[N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
void dfs(int x)
{
if((x<<1)>m) id[++cnt]=x;
if((x<<1)<=m) dfs(x<<1);
if((x<<1|1)<=m) dfs(x<<1|1);
}
db win(int x,int y){return (db)a[x]/(db)(a[x]+a[y]);}
void calc(int x)
{
int l=x<<1,r=l|1;
for(int k=0;k<2;++k)
{
for(int i=0;i<(int)f[l].size();++i)
{
int A=f[l][i].fi;db B=0;
for(int j=0;j<(int)f[r].size();++j) B+=win(A,f[r][j].fi)*f[r][j].se;
f[x].pb(mkp(A,B*f[l][i].se));
}
swap(l,r);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("K.in","r",stdin);
freopen("K.out","w",stdout);
#endif
n=read();m=n*2-1;
for(int i=1;i<=n;++i) a[i]=read();
a[0]=a[1];a[1]=0;sort(a+1,a+n+1);a[1]=a[0];
dfs(1);
for(int i=1;i<=n;++i) f[id[n-i+1]].pb(mkp(i,1));
for(int i=m-n;i;--i) calc(i);
for(int i=0;i<(int)f[1].size();++i)
if(f[1][i].fi==1) printf("%.10lf\n",f[1][i].se);
return 0;
}