The 2023 ICPC Asia Regionals Online Contest (2) MDIELK
M Dirty Work
题意:总共有\(n\)个问题,对于第\(i\)个问题需要\(a_i\)分钟。你可以随便选择一个没过的题去写,写完以后马上交,你有\(p_i\)的概率会错,错了不能跳题,你要花额外\(b_i\)的时间去\(debug\)。问你以最佳策略的最小罚时。
思路:因为有基础罚时(即做完这个题的总时间),那么问题变成求前缀和的和的最小值。那么把小的放前面即可(每个值为\(a_i+b_i*p_i\))。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
double a[N],b[N],p[N],s[N];
int main()
{
//ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n; i++)
{
cin>>a[i]>>b[i]>>p[i];
s[i] = a[i]+p[i]*b[i];
}
sort(s+1,s+1+n);
double ans = 0;
for(int i = 1;i <= n; i++)
s[i] += s[i-1],ans += s[i];
printf("%.12lf\n",ans);
}
return 0;
}
D Project Manhattan
题意:有\(n\)条水平的直线和\(n\)条垂直的直线交叉形成一个网格图。每一个点有一个花费(可以是负数)。当我们选择点\((i,j)\),那么可以覆盖第\(i\)行和第\(j\)列。问最小花费是多少可以覆盖完所有。
思路:首先,很显然的\(0\)和负数一定要选。又因为要全覆盖,那么每行至少有一个要选,每列至少有一个要选。
两种覆盖策略:
- 覆盖\(n\)行
- 覆盖\(n\)列
那么当我们选完\(0\)和负数之后呢,如果还有没被覆盖的,优先选小的。
注意初始化!!!
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 510;
ll a[N][N];
bool c[N],r[N];
ll minc[N],minr[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
cin>>a[i][j];
memset(minc,127,sizeof(minc));
memset(minr,127,sizeof(minr));
memset(c,false,sizeof(c));
memset(r,false,sizeof(r));
ll ans = 0;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
{
if(a[i][j]<=0)r[i] = true,c[j] = true,ans += a[i][j];
}
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
{
minr[i] = min(minr[i],a[i][j]);
}
for(int j = 1;j <= n; j++)
for(int i = 1;i <= n; i++)
{
minc[j] = min(minc[j],a[i][j]);
}
ll sr = 0,sc = 0;
for(int i = 1;i <= n; i++)
{
if(r[i])continue;
else sr += minr[i];
}
for(int j = 1;j <= n; j++)
{
if(c[j])continue;
else sc += minc[j];
}
cout<<min(sc,sr)+ans<<"\n";
}
return 0;
}
I Impatient Patient
题意:你受伤了,现在要恢复。一开始在恢复的第\(0\)阶段,到第\(n\)阶段才算恢复完全。
第\(i\)天,你可以选择什么都不干就只是休息,那么每天可以恢复一个阶段,那么\(n\)天恢复完全。你可以可以选择挑战自己,如果一旦挑战成功呢,你就会直接恢复完全,否则的话你会回到第\(a_i\)阶段。其中挑战成功的概率是\(p_i\)。
思路:我们连接每一个阶段和能到达的阶段,发现是一个图,每一条边有一个概率。那么因为我们采用的是最佳策略,我们会怎么做呢?我们一定会到达一个成功期望天数最小的点不断挑战。对于第\(i\)天的成功概率是\(p_i\)的话,成功的期望次数是\(\dfrac{1}{p_i}\),那么失败的期望的天数就是\(\dfrac{1}{p_i}-1\)天,每次失败会回到\(a_i\),那么我们又从\(a_i\)走到\(i\)(花费\(i-a[i]\))然后尝试(\(+1\))。注意挑战也要花费\(1\)的天数所以\(+1\)。
那么对于第\(i\)个点的期望天数就是:\((i+1)+(i-a[i]+1)*(\dfrac{1}{p_i}-1)\)。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 5e5 + 10;
const double M = 1e5;
int n;
double a[N],q[N],p[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int t;
cin>>t;
while(t--)
{
cin>>n;
for(int i = 0;i < n; i++)
cin>>a[i];
double ans = n;
for(int i = 0;i < n; i++)
{
double q;
cin>>q;
if(q==0)continue;
double p = q/M;
double tmp = i+1+(1/p-1)*(i-a[i]+1);
ans = min(ans,tmp);
}
printf("%.12lf\n",ans);
}
return 0;
}
E Another Bus Route Problem
题意:有\(n\)个点,\(n-1\)条边,形成一颗树。
给你\(m\)条公交路线,从\(u_i->v_i\)(表示两个点之间最短的树上距离)。我们可以从\(u_i\)或者\(v_i\)上车,可以从\(u_i->v_i\)路径上任何一点下车。问你从\(1\)号点到每一个点至少需要多少条公交路线。
思路:\(bfs\)
考虑从\(1\)(因为我们只能从1上车)做为起点加入队列,花费\(0\)。
然后考虑从\(1\)能到那些点,如果之前没被遍历到,那么去把它加入队列。
然后再以队列里面某个点为起点去往上眺,因为我们一开始是从\(1\)开始的,那么之后的点一定可以到达\(1\)的。如果某个点\(u\)能到达\(1\),那么它的父亲也一定可以,我们也把它的父亲能到的点加入。一直重复,直到队列为空。
注意已经访问过的就不要重复访问了。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n,m,fa[N];
queue<pair<int,int>>q;
int ans[N];
vector<int>e[N];
void find(int u,int d)
{
while(u!=-1)
{
if(ans[u] != -1)return;
ans[u] = d;
// cout<<"u = "<<u<<" d = "<<d<<"\n";
// cout<<"size = "<<e[u].size()<<"\n";
for(auto v : e[u])
if(ans[v] == -1)
q.push({v,d+1});
u = fa[u];
}
return;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
cin>>n>>m;
fa[1] = -1;
for(int i = 2;i <= n; i++)
cin>>fa[i];
for(int i = 1;i <= m; i++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1;i <= n; i++)
ans[i] = -1;
q.push({1,0});
while(!q.empty())
{
auto x = q.front();
q.pop();
find(x.first,x.second);
}
for(int i = 2;i <= n; i++)
cout<<ans[i]<<" ";
cout<<"\n";
return 0;
}
L Super-palindrome
题意:我们定义,如果能把\(S\)拆成偶数个部分,并且\(S_i = S_{2k-i+1}\),我们称之为超级回文串。给你一个串\(S\),让你去找它有多少个超级回文子串。
思路:哈希+双指针
我们对于每个点\(l_1 = i\)和\(r_1 = i+1\),去向两边扩展,直到找到离它最近的满足\(S_{l_1,r_1}=S_{l_2,r_2}\),统计答案,并更新\(r_1 = l_1-1,l_2 = r_2+1\)
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
typedef pair<long long, long long> pll;
struct DoubleStringHash
{
vector<long long> h1, h2, w1, w2;
long long base1 = 131, base2 = 13331;
long long 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;
}
}
pll 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;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int t;
cin>>t;
while(t--)
{
string s;
cin>>s;
int sz = s.size();
ha.init(s);
s = "?"+s;
ll ans = 0;
for(int i = 1;i < sz; i++)
{
int l1 = i,r1 = i;
int l2 = i+1,r2 = i+1;
while(l1>=1&&r2<=sz)
{
if(ha.get(l1,r1)==ha.get(l2,r2))
{
//cout<<"l1 = "<<l1<<" r1 = "<<r1<<" l2 = "<<l2<<" r2 = "<<r2<<"\n";
ans++,r1 = l1-1,l2 = r2+1;
}
l1--,r2++;
}
}
cout<<ans<<"\n";
}
return 0;
}
K Super-knight
题意:一开始你在 \((0,0)\),每次你可以走\((+a,+b)\)。
假设当前的点是\((x,y)\),那么你可以走到的点是\(((x+a)\%n,(y+b)\%n)\)
问你能走到的离\((0,0)\)最近的点的欧几里得距离的平方。
思路:我们发现最终的答案一定在红色框框内。
所以只有当它越界了才有可能是答案。
那么如果当前的坐标是\((x,y)\),那么如果我要走到越界,那么我需要走\(min(\dfrac{n-x+a-1}{a},\dfrac{n-y+b-1}{b})\)
如果当我们走到之前走过的那就停止,因为之后都是一样的了。对于所有可能的答案取个\(min\)即可。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
inline __int128 read(){__int128 x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
inline void write(__int128 x){if (x < 0){putchar('-');x = -x;}if (x > 9) write(x / 10);putchar(x % 10 + '0');}
typedef __int128 ll;
int main()
{
//ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int t;
cin>>t;
while(t--)
{
ll n,a,b;
a = read(),b = read(),n = read();
ll x = a,y = b;
map<pair<ll,ll>,int>mp;
x %= n,y %= n;
ll ans = 100*100*2;
while(mp.find({x,y})==mp.end())
{
mp[{x,y}] = 1;
ll tmp = x*x+y*y;
if(tmp==0)break;
ans = min(ans,tmp);
ll step = min((n-x+a-1)/a,(n-y+b-1)/b);
x += a*step;
y += b*step;
x %= n,y %= n;
}
write(ans),cout<<"\n";
}
return 0;
}
- Regionals Contest Online MDIELK 2023regionals contest online mdielk regionals contest online 2023 regionals contest online 2022 regionals contest online string regionals游记contest online regionals contest online abefj periodicity regionals contest problem regionals multiply contest problem 地球2023.11版本online online 2023 test