zoukankan      html  css  js  c++  java
  • 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 "
    "
    //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 "
    "
    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
    ";
    		else if(c>1){
    			long long zs = sqrt(c);
    			if(zs*zs==c) cout<<"yes
    ";
    			else cout<<"no
    ";
    		}
    		else cout<<"no
    ";
    	}
    	return 0;
    }
    

      

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

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

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

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

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

    3时22min时过的

    #include <bits/stdc++.h>
    using namespace std;
    #define endl "
    "
    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("
    ");
    	}
    	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
    ",fz);
    	return 0;
    }
    

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

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

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

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

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

  • 相关阅读:
    网络编程1:网络模型
    window10解决需要管理员删除文件的权限问题
    嵌入式框架iframe
    布局框架frameset
    JDBC连接mysql
    springboot插件
    Win10安装 oracle11g 出现INS-13001环境不满足最低要求解决方法
    卸载虚拟机
    Maven
    mysql-数据备份与还原
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/13876050.html
Copyright © 2011-2022 走看看