2019ccpc女生赛+补题

        这周末要打女生赛了,想着和队友练一场,在cf只找到2021年的,由于去年那场打过就不再打了,杭电oj上面最近的也是2019年的,就打了这场。不过题面真的是。。。一言难尽,tree那题题面说三棵树其实是一棵树,Tetris俄罗斯方块那题是道签到,题面input一行两个整数实际上是多行输入,一直以为思路错了卡了很久。。。。。。改成多行输入就对了。

ps:在这个页面交不了题,只能看题,在题库中对应题号是6544-6554.。

2019ccpc女生赛+补题_第1张图片

2019ccpc女生赛+补题_第2张图片

 1001-Ticket

思路:

签到,只需记录当前共消费多少,每次买票时根据总消费加上打折的票价。

代码:

#include
const int maxn=1010;
using namespace std;
#define ll long long
double n,a[maxn];
int main()
{
	double sum=0;
	double res=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(sum<100)sum+=a[i];
		else if(sum>=100&&sum<150)sum+=a[i]*0.8;
		else if(sum>=150&&sum<400)sum+=a[i]*0.5;
		else sum+=a[i];
	}
	printf("%.2lf\n",sum);
	
	return 0;
}

1002-Gcd

思路:

将1-n的数分为两组,使得这两组数的gcd最大。

也是签到。

直接求1-n的和sum的第二大公因数,第一大公因数是sum本身,要分成两组数所以必不可能为sum,因此找第二大公因数。若a%x==0,b%x==0,则一定有(a+b)%x==0.只要其中一堆数和为第二大公因数即可。

代码:

#include 
using namespace std;
typedef long long ll;
ll n;
int main(){
	cin>>n;
	ll sum=(1+n)*n/2;
	int temp=1;
	for(int i=2;i<=sqrt(sum);i++)
	{
		if(sum%i==0)
		{
			cout<

1003-Functon

思路:

这题是学姐写的,没读题。

代码:

#include 
using namespace std;
#define N 1000005
typedef long long ll;
struct node{int idx;ll x;ll val;};
bool operator < (node a,node b){return a.val>b.val;}
bool operator > (node a,node b){return a.val>n>>m;
	priority_queue q;
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
		ans+=a[i]+b[i]+c[i];
		q.push({i,1,3*a[i]+b[i]});
	}
	m-=n;
	while(m--)
	{
		node t=q.top();q.pop();
		ans+=t.val;
		t.x=t.x+1;
		t.val=2*a[t.idx]*t.x+a[t.idx]+b[t.idx];
		q.push(t);
	}
	cout<

1004-Tree

思路:

训练时没写出来,感觉是数据结构题,应该可以用线段树写,但是学的不精不会写。

赛后看了一下题解说是树链剖分板子题,马上去学了树链剖分,补了。

树链剖分+线段树维护。

n个节点n-1条边,保证无环,因此相当于是一棵树,任意两个节点之间的路径实际上只有一条,所以不需要计算最短路径。

原本每次修改区间上的节点可能会超时,但由于同个节点修改不超过10次之后节点权值最多只能是1,因此加一个maxx判断当前节点区间最大值,如果在修改时发现最大值为1那么就不需要再修改了,这样复杂度就不会超时。

代码:

#include
#define ll long long
const int N=1e5+10,M=N*2;
using namespace std;
inline ll max(ll a,ll b){return a > b ? a : b;}
int n,m,cnt,idx;
int id[N],nw[N],dep[N],sz[N],top[N],fa[N],son[N],w[N],h[N],e[M],ne[M];
//w[N]存节点权值,e[N],ne[N]邻接表存人数
//id[N]存节点dfs编号,nw[N]存每个编号(dfs)的权值,dep[N]存每个节点深度,sz[N]存以节点为根的子树大小
//top[N]存每个重链顶点,fa[N]存每个节点父节点,son[N]存每个节点重儿子,e[N]存边节点
struct tree
{
  int l,r;
  ll maxx,sum;
}tr[N*4];//线段树
void add(int a,int b)
{
  //存边,更新邻接表
  e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//dfs所有节点的重儿子,更新树节点信息
void dfs1(int u,int father,int depth)
{
  dep[u]=depth,fa[u]=father,sz[u]=1;
  for(int i=h[u];~i;i=ne[i])//遍历u邻接表
  {
    int j=e[i];
    if(j==father) continue;//当前边节点为父节点
    dfs1(j,u,depth+1);
    sz[u]+=sz[j];//更新以u为根节点的子树大小;
    if(sz[son[u]]>1;
  build(u<<1,l,mid);build(u<<1|1,mid+1,r);
  pushup(u);
}
//线段树进行修改并更新
void update(int u,int l,int r)
{
  if(tr[u].maxx<=1)return;
  if(tr[u].l==tr[u].r)//当前为叶子节点,更新
  {
    tr[u].maxx=sqrt(tr[u].maxx);
    tr[u].sum=sqrt(tr[u].sum);
    return;
  }
  int mid=tr[u].l+tr[u].r>>1;
  if(l<=mid&&tr[u<<1].maxx>1)update(u<<1,l,r);
  if(r>mid&&tr[u<<1|1].maxx>1)update(u<<1|1,l,r);
  pushup(u);
}
//线段树进行查询区间和
ll query(int u,int l,int r)
{
  if(l<=tr[u].l&&r>=tr[u].r)return tr[u].sum;
  int mid=tr[u].l+tr[u].r>>1;
  ll res=0;
  if(l<=mid) res+=query(u<<1,l,r);
  if(r>mid) res+=query(u<<1|1,l,r);
  return res;
}
//更新节点之间路径
void update_path(int u,int v)
{
  while(top[u]!=top[v])//当两个节点的重链的头节点不一样,即不在一条重链上,优先走更低的重链
  {
    if(dep[top[u]]

1005-checkout

思路:

这题代码也是学姐写的,没读题。

代码:

#include 
using namespace std;
typedef long long ll;
#define N 1000005
ll n,m,cnt[N],ans=0,a,b;
int fa[N],color[N];
vector v[N];
map,ll> mp;
map mpp;
void dfs(int u,int f)
{
	fa[u]=f;
	if(color[u]==color[f]) cnt[u]++;
	for(auto i:v[u])
	{
		if(i==f) continue;
		mp[{u,color[i]}]++;
		if(color[i]==color[u]) cnt[u]++,ans++;
		dfs(i,u);
	}
	mpp.clear();
	for(auto i:v[u]) 
	{
		ll x=mp[{u,color[i]}];
		if(x>0) cnt[i]+=x-1;
		mpp[color[i]]+=x;
	}
	map ::iterator it;
	for(it=mpp.begin();it!=mpp.end();it++) ans+=it->second/2;
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);color[i]=a;
	}
	for(int i=1;i

1007-circle

思路:

没读题,应该也是签到,张钰敏写的,但是一开始好像pi精度没弄好wa了,学姐调了一下就过了。

代码:

#include 
#include 
using namespace std;
typedef long long ll;
const double pi=acos(-1);
int main()
{
	int n;
	while(cin>>n)
	{
		double xita=(2*pi)/n;//每个大扇形角度
		double xita2=xita/2;
		double ans=(n-1)*sin(xita)/2;
		ans+=sin(xita2);
		printf("%.6lf\n",ans);
	}
	return 0;
}

1008-Clock

思路:

是一个分类讨论题。

时分秒针的每种组合都会代表两个时刻,因此对于给出的所有时刻我们都计算对应到0-12点时分秒针的组合,只需要计算总的秒数,排序。

由于我们可以进行两种操作,顺时针和逆时针,所以都求之后取最小值。

排序后找起始位置的左右两端的位置,计算差值,用走一圈的度数-差值,最小的即为答案。注意有可能会有和初始时刻重复的时间。

对于初始时刻排序后的位置分类讨论,如果排序后的初始位置在第一位,那么它左端为最后一个;

如果排序后的初始位置在最后一位,那么它左端为第一个。

一发过了,很开心。

代码:

#include 
const int maxn=9e4;
const int lsum=43200;
using namespace std;
typedef long long ll;
int n;
int h,m,s;
int a[maxn];
int ar,cnt;
double ans;
int suan(int h,int m,int s)
{
	int res=h*60*60+m*60+s;
	if(res>=lsum)return res%lsum;
	else return res;
}
int main()
{
	cin>>n;
	cin>>h>>m>>s;
	a[0]=suan(h,m,s);
	ar=a[0];
	cnt=0;
	for(int i=1;i<=n;i++)
	{
		cin>>h>>m>>s;
		a[i]=suan(h,m,s);
		if(a[i]==ar)cnt++;//标记有几个初始时刻
	}
	sort(a,a+1+n);
	int temp=0;
	for(int i=0;i<=n;i++)
	{
		if(a[i]==ar)
		{
		  temp=i;
		  break;
		}
	}
	int x=0,y=0;
  if(cnt==n)cout<<"0.00"<

1010-Tangram

思路:

这题也是学姐写的。

七巧板画线,第一次画线多六块,往后每次画线增加的都是之前增加的块数加1;

即:

0:7

1:7+6

2:7+6+7

3:7+6+7+8

......

代码:

#include 
using namespace std;
typedef unsigned long long ll;
ll n,t;
int main(){
	while(cin>>n)
	{
		cout<<7+6*n+((n-1)*n)/2<

1011-Tetris

思路:

n,m<=12,范围很小,手画了几个感觉只有当n,m是4的倍数时才可以刚好填满。

猜测样例给的4x4是能组成的最小块。

当n,m是4的倍数时,k1=n/4,k2=m/4;输出k1*k2个最小块即可。

注意该题在杭电oj上是多个样例输入。

代码:

#include 
using namespace std;
typedef long long ll;
char a[10][10];
int main()
{
	int n,m;
	a[1][1]='1',a[1][2]='1',a[1][3]='1',a[1][4]='3';
	a[2][1]='2',a[2][2]='1',a[2][3]='3',a[2][4]='3';
	a[3][1]='2',a[3][2]='2',a[3][3]='4',a[3][4]='3';
	a[4][1]='2',a[4][2]='4',a[4][3]='4',a[4][4]='4';
	while(cin>>n>>m)
	{
		if((n%4==0)&&(m%4==0))
		{
			int aa=n/4;
			int bb=m/4;
			for(int i=1;i<=aa;i++)
			{
				for(int h=1;h<=4;h++)
				{
					for(int j=1;j<=bb;j++)
					{                                                                                                                                       
						for(int w=1;w<=4;w++)cout<

你可能感兴趣的:(ccpc,杭电hdu,oj,算法,c++,数据结构)