【CF套题】 Gym101623 NWERC2017

【前言】
在BZOJ上翻题看到了几题,心血来潮就全写了。
C这个搜索我不是很会写,直接看了别人的(然而还是没写)
然后这个J让我知道一定不能在还要用值的时候删掉一个指针。

【题目】
原题地址

A.Ascending Photo

单独写

B.Boss Battle

显然每次可以缩减一个可能的位置,所以若 n ≤ 3 n\leq 3 n3则答案为 1 1 1,否则答案就是 n − 2 n-2 n2

#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+ri的位置会变成 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值