2020CCPC威海,第一次参赛
第一次参赛,很不错的体验
因为疫情的原因,不能线下打了qwq,不过体验还是很不错的
早上7点多起,吃个面包,8点到场,然后就看看腾讯会议上其他学校的队伍发呆,看看队友玩原神,把屏幕录制开起来 ,屏幕录制是2帧的,可以 帧 间 作 弊( 误 )
比赛时同时只能使用一个IDE(不知道为什么),不过我们也只用得到Dev 。
字典的话,我们三人都没,就没带233 ,不过影响也不大,都是靠的样例推的题目意思(
打印机我们比赛时也没用到 。
9点了,我们一开始的分配是一个队友开前4题,另一个队友开中4题,我开后4题,我们先是都看了下H题,然后一个队友开始看A,我和另一个队友看H 。
刚开始的时候,好多人交A题,全wa了,然后我们队看样例过了也莽交了一发wa了,我们就一起分析,然后我看样例察觉到2n个人都过桥后,工具人是留在左端的,
于是就变成了一个 先走 还是 先等2号后走 的问题,这个问题我们还分析了挺久,代码写的也很复杂,用了三目运算符,交的时候有种很可能wa的感觉,还好过了 。
42min时过了,比赛时的AC代码:
#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时才过,一遍过的
来欣赏下我丑陋无比的代码(
#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时过
#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时过的
#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次提交。。。。
纪念第一次参赛,小小甜心牛逼!

浙公网安备 33010602011771号