2020CCPC威海,第一次参赛

第一次参赛,很不错的体验

因为疫情的原因,不能线下打了qwq,不过体验还是很不错的

早上7点多起,吃个面包,8点到场,然后就看看腾讯会议上其他学校的队伍发呆,看看队友玩原神,把屏幕录制开起来 ,屏幕录制是2帧的,可以 帧 间 作 弊( 误 )

比赛时同时只能使用一个IDE(不知道为什么),不过我们也只用得到Dev 。

字典的话,我们三人都没,就没带233 ,不过影响也不大,都是靠的样例推的题目意思( 

打印机我们比赛时也没用到 。

9点了,我们一开始的分配是一个队友开前4题,另一个队友开中4题,我开后4题,我们先是都看了下H题,然后一个队友开始看A,我和另一个队友看H 。

刚开始的时候,好多人交A题,全wa了,然后我们队看样例过了也莽交了一发wa了,我们就一起分析,然后我看样例察觉到2n个人都过桥后,工具人是留在左端的,

于是就变成了一个 先走 还是 先等2号后走 的问题,这个问题我们还分析了挺久,代码写的也很复杂,用了三目运算符,交的时候有种很可能wa的感觉,还好过了 。

42min时过了,比赛时的AC代码:

 

A. Golden Spirit
 
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
//const int MAXN = ;
//const int INF = 0x3f3f3f3f;

int T;
long long n, x, t;
unsigned long long ans;

int main(void)
{
	// 1000000000
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> T;
	while (T--)
	{
		ans = 0;
		cin >> n >> x >> t;
		ans += 2 * n * t;
		if ((2 * n - 2) * t  >= x)
		{
			ans *= 2;
		}
		else
		{
			ans += (x - (2 * n - 2) * t) > t ? (t > (x - (2 * n - 1) * t) ? t : (x - (2 * n - 1) * t)) : (x - (2 * n - 2) * t);
			ans += 2 * n * t;
		}
		cout << ans << endl;
	}	
	return 0;
 } 

  

 

然后我们就研究H题了,容易想到是一个差分,但是数组难开,为了减少空间,要开vector,然后自己在草稿纸上开了好多数组,关系很复杂,队友1过A后,我开始写H,写的时候卡壳了,数组又开不来了,

又开始重新构思,后来二分查找又写不来了。。我连二分查找都写不来了,还得请队友帮忙,后来跟队友讲了我的做法后,他提出了一种O(1)处理的办法,就不用二分了,感谢队友的指点,提供了很大的帮助,不过我还是写的很丑陋就是了。。队友:你怎么写的那么复杂

写了差不多1小时? 1时48min时才过,一遍过的

来欣赏下我丑陋无比的代码( 

H. Message Bomb
 
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
const int MAXN = 2e5 + 7;
//const int INF = 0x3f3f3f3f;

int n, m, s;
int t, x, y;
vector<int> su[MAXN];
vector<int> id[MAXN],fid[MAXN];
vector<pair<int ,int > >nbr[MAXN];
int fa[MAXN];
bool vis[MAXN];
int dd[MAXN];
int ans[MAXN];
int main(void)
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n >> m >> s;
	
	for( int i = 1;i<=s;i++)
	{
		cin >> t >> x >> y;
		if(t == 1){
			nbr[x].push_back(make_pair(y,su[y].size()));
			id[x].push_back(y);
		}
		if(t == 2){
			nbr[x].push_back(make_pair(y,su[y].size()));
			id[x].push_back(y);
		}
		if(t == 3) {
			fa[x]++;
			su[y].push_back(i);
		}	
	}
	for(int i = 1;i<=m;i++){
		for(int j = 0;j < id[i].size();j++){
			vis[id[i][j]] = false;
		}
		for(int j = 0;j < nbr[i].size();j++ ){
			int gu = nbr[i][j].first;
			int sjs = nbr[i][j].second;
			if(!vis[gu]) {
				dd[gu] = sjs;
				vis[gu] = true;
			}
			else{
				vis[gu] = false;
				ans[i] += sjs - dd[gu];
			}
		}
		for(int j = 0 ;j<id[i].size();j++){
			int  gu = id[i][j];
			if(vis[gu]){
				vis[gu] = false;
				ans[i] += su[gu].size() - dd[gu];
			}
		}
		ans[i] -=fa[i];
	}
	for(int i = 1;i<=m;i++){
		cout<<ans[i]<<endl;
	}
	return 0;
 } 

  

然后我就看D题了,这时队友开了D和L这两个和质数有关的题

D题和队友研究出来是判断c是否能被一个质数的平方整除,c是大到1e18的,我的第一反应就是筛1e9的素数,而且还是用欧拉筛,我当时真的以为能在时间范围内筛出来

既然筛1e9不行,那就筛小一点,然后我就干脆不筛了,就直接暴力

for(int i = 2;i<=1e8;i++){
    if(c%(i*i) == 0)   {
        flag = true;
        break;
    }   
    if(c%i==0) c/=i;  
}

  

也就是只要c不够大的情况下,我是能判断出来yes还是no的,至于c足够大的情况下,我就当它是no 2333

样例肯定能过,然后就交上去了,TLE了,于是我就把那个1e8改小点,还是T了,再改小,改到不T为只,果然wa了233

然后我就在这个地方思考,突然想到一个点,跟队友解释了一下,我暴力过滤掉小于1e6的素数后,最多只剩下两个素数了,我们就判断这两个素数是否相同即可

我把最初的1e8改成2e6,再求个sqrt再平方来判断,就过了

AC的那一刻队友真的特别激动,都跳起来了,队友本来想用大数素数分解的板子,但我们没带这个板子,我都不知道有这个板子 。

因为是打星参赛,所以交的很莽

2时29min时过

D. ABC Conjecture
 
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
	int T;
	long long c;
	cin>>T;
	while(T--){
		cin>>c;
		bool flag = false;
		int cnt = 0;
		for(long long i = 2;i*i<=c&&i<=(long long)2e6;i++){
			if(c%(i*i)==0) {
				flag = true;
				break;			
			}
			if(c%i==0){
				c/=i;
				cnt++;
			}
		}
		if(flag) cout<<"yes\n";
		else if(c>1){
			long long zs = sqrt(c);
			if(zs*zs==c) cout<<"yes\n";
			else cout<<"no\n";
		}
		else cout<<"no\n";
	}
	return 0;
}

  

之后就看另一道素数题,L题了

这题范围就小多了,我研究了下,感觉很有背包的意思,就分析出来是分组背包了,

这时候午饭来了,我和一位队友开始吃午饭,另一位队友写分组背包,午饭的菜还挺好吃的,鱼有点辣好吃,还有苹果和酸奶 。

吃完午饭后就开始帮队友调分组背包了,样例过了之后,PE了一发 ?又wa了一发,一开始dp数组是开int的,然后改成long long,发现long long也会爆,

应该要及时取对数,然后我们再转移方程里取对数,就T了,最后把物品的价值去对数,就过了

3时22min时过的

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
const int MAXN = 3e4 + 7;
//const int INF = 0x3f3f3f3f;

int n;
int cnt;
vector<pair<int ,long double> > prime[MAXN];
bool vis[MAXN];
long double dp[30007];

void GetPrime()
{
	memset(vis, false, sizeof(vis));
	cnt = 0;
	for (int i = 2; i < MAXN; ++i)
	{
		if (!vis[i])
			prime[++cnt].push_back(make_pair(i,log(i)));
		for (int j = 1; j <= cnt && i <= MAXN / prime[j][0].first; ++j)
		{
			vis[i * prime[j][0].first] = true;
			if (i % prime[j][0].first == 0)
				break;
		}
	}
	//cout << cnt << endl;
}

void init()
{
	for (int i = 1; i <= cnt; ++i)
	{
		int nxt = prime[i][0].first * prime[i][prime[i].size() - 1].first;
		while (nxt < 3e4 + 7)
		{
			prime[i].push_back(make_pair(nxt,log(nxt)));
			nxt *= prime[i][0].first;
		}		
	}
}

void solve()
{
	dp[0] = 0;
	for (int i = 1; i <= 30000; ++i)
		dp[i] = 0;
	for (int i = 1; i <= cnt; ++i)
	{
		for (int v = 30005; v; --v)
		{
			for (int j = 0; j < prime[i].size(); ++j)
			{
				if (v >= prime[i][j].first)
					dp[v] = max(dp[v], dp[v - prime[i][j].first] + prime[i][j].second);
			}
			dp[v] = max(dp[v], dp[v - 1]);
		}
	}
}

int main(void)
{
//	ios::sync_with_stdio(false);
//	cin.tie(0); cout.tie(0);
	GetPrime();
	init();
	solve();
	int T; 
	cin>>T;
	while(T--)
	{
		cin >> n;
		//cout << dp[n] << endl;
		printf("%.9Lf", (long double)dp[n]);
		if (T > 0)
			printf("\n");
	}
	return 0;
 } 

  

过完L题,就把两道素数题解决了,这时候放松下来边吃苹果边看C题,是一道树的题+概率的题,感觉挺难的,一开始我还想着怎么选目的顶点,一直没想出什么,

然后队友提出了边的贡献的想法,我们研究了下每一条边的贡献是怎么算的,我一下知道怎么写了,不过写的时候还是队友提供了很多帮助,wa了两发,int改long long,long long 还是被爆了,要提前除分母 。 

4时35min时过的

C. Rencontre

 

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 2e5+7;
struct EDGE{
	int to,next;
	long long w;
}edge[MAXN*2];
int tot,head[MAXN];
void add(int u,int v,long long w){
	tot++;
	edge[tot].to = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot;
} 
long long fm = 1;
long long siz[4][MAXN];
void dfs(int st,int f){
	for(int i = head[st];i;i=edge[i].next){
		int po = edge[i].to;
		if(po == f) continue;
		dfs(po,st);
		for(int t = 1;t<=3;t++) siz[t][st] += siz[t][po];
	}
}
long double dfs2(int st,int f){
	long double res = 0;
	for(int i = head[st];i;i = edge[i].next){
		int po = edge[i].to;
		if(po == f) continue;
		long long w = edge[i].w;
		res +=  ((long double)siz[1][po] * (siz[2][1] - siz[2][po]) * (siz[3][1] - siz[3][po])
				+(long double)siz[2][po] * (siz[1][1] - siz[1][po]) * (siz[3][1] - siz[3][po])
				+(long double)siz[3][po] * (siz[1][1] - siz[1][po]) * (siz[2][1] - siz[2][po]) 
				+(long double)siz[1][po] * siz[2][po] * (siz[3][1] - siz[3][po])
				+(long double)siz[1][po] * siz[3][po] * (siz[2][1] - siz[2][po])
				+(long double)siz[2][po] * siz[3][po] * (siz[1][1] - siz[1][po])
				) / (long double)fm * w;
		res+=dfs2(po,st);			
	}
	return res;
}
int main()
{
	int n;
	cin>>n;
	int u,v;
	long long w;
	for(int i = 1; i <= n-1; i++){
		scanf("%d%d%lld",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	long long k;
	for(int i = 1; i <= 3; i++){
		cin>>k;
		fm*=k;
		int tt;
		for(int j = 1;j <= k; j++) {
			scanf("%d",&tt);
			siz[i][tt]++;
		}
	}	
	dfs(1,-1);
	long double fz = dfs2(1,-1);
	//long double ans = (long double)fz / (long double) fm;
	//cout<<fz<<endl<<fm<<endl;
	printf("%.12Lf\n",fz);
	return 0;
}

跟榜开的题,这次榜没歪,打的很好  

完全看完的题有5题,过了5题,第1、2、3、4、5小时各一题

打的很不错,H题之后发挥的很好

 

唯一不足的就是罚时太高了,我们队5题罚时第二高,做的太慢了,也太莽了 。排在我们下面一名的那队是5题罚时第一高,A题9次提交,H题11次提交。。。。

纪念第一次参赛,小小甜心牛逼!

posted @ 2020-10-25 23:56  beta_dust  阅读(952)  评论(6编辑  收藏  举报