湖南省第十八届大学生计算机程序设计竞赛(HNCPC2022)

发布时间 2023-04-17 11:35:45作者: magicat

发现没有题解,我来随便记录下

湖南省第十八届大学生计算机程序设计竞赛(HNCPC2022)

VP情况

队友卡I占了机时导致罚时有点爆炸,也是策略的失误
6题837罚时
补到GH就结束
image

J

判断斐波那契区间有没有一段的和等于\(n\)
由于\(n \leq 10^{15}\)直接暴力即可

#include<bits/stdc++.h>

using namespace std;

long long f[110];
int cnt;
void init()
{
	f[1] = 1, f[2] = 1;
	cnt = 2;
	while(f[cnt] <= 1e15)
	{
		f[cnt + 1] = f[cnt] + f[cnt - 1];
		cnt++;
	
	}
	
}

int main()
{
	init();
	long long n;
	while(cin>>n)
	{
		bool ok = false;
		for(int i = 1; i <= cnt; i++)
		{
			long long sum = 0;
			for(int j = i; j <= cnt; j++)
			{
				sum += f[j];
				if(sum == n)
				{
					ok = true;
				}
				else if(sum > n)
					break;
			}
		
		}
		if(ok)
			cout<<"YES"<<endl;
		else 
			cout<<"NO"<<endl;		
	}
}

K

判断字符串有没有不是前缀的字串与字符串的前缀相等,打印所有符合条件的字串长度

队友告诉我这是kmp的性质,但我忘记kmp是什么了,直接双hash + 二分过了,枚举字串起点,二分满足条件的字串长度

//  AC one more times
#include <bits/stdc++.h>
using namespace std;


 

#define int long long 
typedef pair<int, int> PII;
struct DoubleStringHash
{
    // #define int long long 
    vector<int> h1, h2, w1, w2;
    int base1 = 131, base2 = 13331;
    int p1 = 1e9+7, p2 = 1e9+9;
    void init(string s) {
        int len = s.size();
        s = " " + s;
        h1.resize(len + 1), w1.resize(len + 1);
        h2.resize(len + 1), w2.resize(len + 1);
        h1[0] = 0, w1[0] = 1;
        h2[0] = 0, w2[0] = 1;
        for(int i = 1; i <= len; i++) {
            h1[i] = (h1[i - 1] * base1 + s[i]) % p1, w1[i] = w1[i-1] * base1 % p1;
            h2[i] = (h2[i - 1] * base2 + s[i]) % p2, w2[i] = w2[i-1] * base2 % p2;
        }
    }
    pair<int, int> get(int l, int r) {
        return {(h1[r] - h1[l - 1] * w1[r - l + 1] % p1 + p1) % p1, (h2[r] - h2[l - 1] * w2[r - l + 1] % p2 + p2) % p2};
    }
}ha;

bool cmp(string a, string b) {
    return a.size()<b.size();
}

string s;
void solve()
{
	int n = s.size();
	ha.init(s);
	s = "?" + s;
	long long ans = 0;
	for(int i = 2; i <= n; i++)
	{
		if(s[i] == s[1])
		{
			int l = 1, r = n - i + 1;
			while(l < r)
			{
				int mid = (l + r + 1) >> 1;
				//cout<<i <<"   "<<i + mid - 1<<"   "<<1<<"   "<<mid<<endl;
				if(ha.get(i, i + mid - 1) == ha.get(1, mid))
					l = mid;
				else r = mid - 1;
			}
			//cout<<i<<" " <<l <<endl;
			int t = l;
			ans += (t * t + t) / 2ll;
		}	
	}
	cout<<ans<<endl;
    return;
}

  
signed main()
{
    std::ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
  
	while(cin>>s)
    {
        //cout << "Case #" << tc << ": ";         
        solve();
    }


    return 0;
}

D

矩阵乘法,但直接做会T,队友手推了一下式子发现,\(A\)\(B\)矩阵的元素是一行或一列地去用,但具体观察到的式子留在了我队友的草稿纸上,手推一下也不难,大学生应该都写过线代了吧

#include<bits/stdc++.h>

using namespace std;

#define int long long 
typedef long long ll;
int n;
ll a1,a2,b1,b2;
int A[1010][1010];
int B[1010][1010];
int ca[1010];
int rb[1010];
const int mod = 1e9 + 7;
void solve()
{	

	memset(ca, 0 ,sizeof ca);
	memset(rb, 0 ,sizeof rb);
	
	cin>>a1>>a2>>b1>>b2;
	for(int i = 1; i <= n; i++)	
		for(int j = 1; j <= n; j++)
		{
		
			A[i][j] = (i - 1) * a1 + (j - 1) * a2;
			B[i][j] = (i - 1) * b1 + (j - 1) * b2;
		}
	for(int j = 1; j <= n; j++)
	{
		for(int i = 1; i <= n; i++)
		{
			ca[j] += A[i][j];
			ca[j] %= mod;
		}
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			rb[i] += B[i][j];
			rb[i] %= mod;
		}
			
	}			
	
	int ans = 0;
	for(int i = 1; i <= n; i++)
	{
		ans += (ca[i] * rb[i]);
		ans %= mod;
	}
	cout<<ans<<endl;
}

signed main()
{
	
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	int t = 1;
	//cin>>t;
	while(cin>>n)
	{
		solve();
	}
	
	return 0;
	
}

A

队友告知我这题要维护树上区间修改,树上区间查询最小值,一样树链剖分 + 线段树的裸题,直接改改板子

//  AC one more times
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define endl '\n'
#define all(x) (x).begin(), (x).end()
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<long long,long long> PLL;

const int N = 4e4 + 10;
vector<PII> e[N];
int n, q;
int tot, l[N], r[N], tid[N], top[N], bs[N], sz[N], f[N], dep[N];
LL w[N];
PII edge[N];
void dfs1(int u, int fa)
{
    sz[u] = 1;
    dep[u] = dep[fa] + 1;
    bs[u] = -1;
    f[u] = fa;
    for(auto v : e[u])
    {
        if(v.fi == fa) continue;
        dfs1(v.fi, u);
        w[v.fi] = v.se;
        sz[u] +=sz[v.fi];
        if(bs[u] == -1 || sz[v.fi] > sz[bs[u]])
            bs[u] = v.fi;
    }

}

void dfs2(int u,int t)
{
    l[u] = ++tot;
    tid[tot] = u;
    top[u] = t;
    if(bs[u] != -1)
        dfs2(bs[u], t);
    for(auto v : e[u])
    {
        if(v.fi == bs[u] || v.fi == f[u])    continue;
        dfs2(v.fi, v.fi);
    }
    r[u] = tot;
}

struct info 
{
    int miv;
};
info operator + (const info &a, const info &b)
{
    return (info){min(a.miv, b.miv)};
}


struct segtree
{
    struct info val;
    int tag;
}seg[N * 4];

void update(int id)
{
    seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}

void settag(int id, int tag)
{
    seg[id].tag += tag;
    seg[id].val.miv = seg[id].val.miv + tag;
}

void pushdown(int id)
{
    if(seg[id].tag != 0)
    {
        settag(id * 2, seg[id].tag);
        settag(id * 2 + 1, seg[id].tag);
        seg[id].tag = 0;
    }
}

void build(int id, int l, int r)
{
    seg[id].tag = 0;
    seg[id].val.miv = 10000000;
    if(l == r)
    {
        seg[id].val = {w[tid[l]]};
        //cout<<seg[id].val.miv<<endl;
        return;
    }
    int mid = (l + r) >> 1;
    build(id * 2, l, mid);
    build(id * 2 + 1, mid + 1, r);
    update(id);
}

void modify(int id, int l, int r, int ql, int qr, int tag)
{
    if(ql > qr || l > r) return;
    if(l == ql && r == qr)
    {
        settag(id, tag);
        return;
    }
    pushdown(id);
    int mid = (l + r) >> 1;
    if(qr <= mid)
        modify(id * 2, l, mid, ql, qr, tag);
    else if(ql > mid)
        modify(id * 2 + 1, mid + 1, r, ql, qr, tag);
    else 
    {
        modify(id * 2, l, mid, ql, mid, tag);
        modify(id * 2 + 1, mid + 1, r, mid + 1, qr, tag);
    }
    update(id);
}

info query(int id, int l, int r, int ql, int qr)
{
    if((ql > qr || l > r)) return (info){100000000};
    if(l == ql && r == qr)
    {
        return seg[id].val;
    }
    pushdown(id);
    int mid = (l + r) >> 1;
    if(qr <= mid)
        return query(id * 2, l, mid, ql, qr);
    else if(ql > mid)
        return query(id * 2 + 1, mid + 1, r, ql, qr);
    else 
    {
        return query(id * 2, l, mid, ql, mid) +
        query(id * 2 + 1, mid + 1, r, mid + 1, qr);
    }
    update(id);

}

void modify(int u, int v, int k)
{

    while(top[u] != top[v])
    {
        if(dep[top[u]] > dep[top[v]])
        {
            modify(1, 1, n, l[top[u]], l[u], k);
            //cout<<query(1, 1, n, l[top[u]], l[u]).miv<<endl;
            u = f[top[u]];
        }
        else
        {
            modify(1, 1, n, l[top[v]], l[v], k);
            //cout<<query(1, 1, n, l[top[v]], l[v]).miv<<endl;
            v = f[top[v]];
        }
    }
    if(dep[u] < dep[v]) swap(u, v);
    modify(1, 1, n, l[v] + 1, l[u], k);
    //cout<<query(1, 1, n, l[v] + 1, l[u]).miv<<endl;
}

info query(int u, int v)
{
    info ans = (info){100000000};
    while(top[u] != top[v])
    {
        if(dep[top[u]] > dep[top[v]])
        {
            ans = ans + query(1, 1, n, l[top[u]], l[u]);
            u = f[top[u]];
        }
        else
        {
            ans = ans + query(1, 1, n, l[top[v]], l[v]);
            v = f[top[v]];
        }
        //cout<<ans.miv<<endl;
    }
    if(dep[u] < dep[v]) swap(u, v);
    ans = ans + query(1, 1, n, l[v] + 1, l[u]);
       // cout<<ans.miv<<endl;
    
	return ans;
}

void init()
{
	tot = 0;
	
	for(int i = 1; i <= n; i++)
	{
		e[i].clear();
		l[i] = 0;
		r[i] = 0;
		tid[i] = 0;
		top[i] = 0;
		bs[i]  = 0;
		sz[i] = 0;
		f[i] = 0;
		dep[i] = 0;
		w[i] = 0;
		edge[i] = {0, 0};
	}
	for(int i = 1; i <= 4 * n; i++)
	{
		seg[i].tag = 0;
		seg[i].val.miv = 1000000;
	}
}
void solve()
{
/*
vector<PII> e[N];
int n, q;
int tot, l[N], r[N], tid[N], top[N], 
bs[N], sz[N], f[N], dep[N];
LL w[N];
PII edge[N];
*/	
/*
5 2
1 2 5
3 1 2
4 3 4
5 3 3
4 2 1
5 2 2
5 2
1 2 5
3 1 2
4 3 4
5 3 3
4 2 1
5 2 2

*/
	init();
	
	cin>>q;
    for(int i = 1; i < n; i++)
    {
        int u, v, w;    cin>>u>>v>>w;
        edge[i] = {u, v};
        e[u].pb({v, w});
        e[v].pb({u, w});
    }
    dfs1(1, 0);
    dfs2(1, 1);
    build(1, 1, n);
    int ans = 0;
    /*
    cout<<"L: "<<endl;
    for(int i = 1; i <= n; i++)
    	cout<<i <<"  L:   "<<l[i]<<endl;
    cout<<"R: "<<endl;
    for(int i = 1; i <= n; i++)
    	cout<<i <<"  R:   "<<r[i]<<endl;
*/
    
    for(int i = 1; i <= q; i++)
    {
        int u, v, w;	cin>>u>>v>>w;
        info t = query(u, v);
        //cout<<"-----------\n";
        if(t.miv < w)
        	continue;
		else
		{
			modify(u ,v, -w);
			ans += w;
			
		}
		//cout<<"QUERY:  "<<i<<"  "<<t.miv<<endl;
		
		//cout<<"TREE:  "<<endl;

    }
	cout<<ans<<endl;
    return;
}

  
int main()
{
    std::ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
  
    int TC = 1;
    
    //cin >> TC;    
    while(cin>>n)
	{
                
        solve();
    }


    return 0;
}

E

小模拟,只需要判断核酸开始营业时间,停业时间和来排队时间的先后顺序和计算题目中给出的公式即可。

#include<bits/stdc++.h>

using namespace std;


typedef long long ll;

struct dot
{
	int h1, m1, h2, m2, h3, m3;	
}he[110];

int n;
int mi[110];
int arr[110][10];
ll ans;
void in()
{
	for(int i = 1; i <= n; i++)
	{
			int h,m;
		string s;	
		char a,b,c,d;
	
		cin>>s;
		a = s[0], b = s[1];
		c = s[3], d = s[4];
		h = (a - '0') * 10 + (b - '0');
		m = (c - '0') * 10 + (d - '0');
		he[i].h1 = h;
		he[i].m1 = m;
	
		cin>>s;
		a = s[0], b = s[1];
		c = s[3], d = s[4];
		h = (a - '0') * 10 + (b - '0');
		m = (c - '0') * 10 + (d - '0');
		he[i].h2 = h;
		he[i].m2 = m;
	
		cin>>s;
		a = s[0], b = s[1];
		c = s[3], d = s[4];
		h = (a - '0') * 10 + (b - '0');
		m = (c - '0') * 10 + (d - '0');
		he[i].h3 = h;
		he[i].m3 = m;
		
		if(he[i].h1 * 60 + he[i].m1 > he[i].h3 * 60 + he[i].m3)
		{
			he[i].h3 = he[i].h1;
			he[i].m3 = he[i].m1;
		}
	
		cin>>mi[i];
		for(int j = 1; j <= mi[i]; j++)
			cin>>arr[i][j];
	}
}
//  1440

void calc(int i)
{
	int base = he[i].h1 * 60 + he[i].m1;
	int y = (he[i].h2 - he[i].h1) * 60 + (he[i].m2 - he[i].m1);	
	
	int st = he[i].h1 * 60 + he[i].m1;
	int pai = he[i].h3 * 60 + he[i].m3;
	if(pai < st)
		he[i].h3 = he[i].h1, he[i].m3 = he[i].m1;
	
	for(int x = 0; x <= y; x++)
	{
		if(x + st < pai)	continue;
		
		ll xx = 1;
		ll cnt = 0;
		for(int j = 1; j <= mi[i]; j++)
		{
			cnt += (arr[i][j] * xx);
			xx *= x;
		} 
		cnt = fabs(sin(cnt) * y);
		if(x + cnt <= y)
		{
			ans = min(ans, base + x + cnt);
		}
		
	}
}
void solve()
{
	in();
	ans = 1e8;
	for(int i = 1; i <= n; i++)
	{
		calc(i);
	}
	if(ans == 1e8)
	{
		cout<<"Oh No!\n";
	}
	else
	{
		int h = ans / 60;
		int m = ans % 60;
		if(h < 10)
		{
			cout<<0;
			cout<<h;	
		}
		else
			cout<<h;
		cout<<":";
		if(m < 10)
		{
			cout<<0;
			cout<<m;	
		}
		else
			cout<<m;
		cout<<endl;
	}
	
}

int main()
{
	
	//ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
	int t = 1;
	//cin>>t;
	while(cin>>n)
	{
		solve();
	}
	
	return 0;
	
}

I

I比较玄学,队友搞了2小时+4发罚时还没出来
我的作法记录这一行中是否有元素\(a\)存在
如何处理询问
分别记录\(x\)\(y\)存在的行,