CCPC2024济南个人题解
A.The Fool / 愚者
题意:给定 \(n\) 行、每行 \(m\) 个连续的字符串,每个字符串长度为 \(k\) ,当中有且仅有一个与其他的字符串不同,找出这个字符串,输出它所在的行和列。
限制条件: \(n,m≤200, k≤10\)。
题解:直接模拟即可,时间复杂度\(O(nmk)\)。
码风这一块
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
//cin>>tttt;
while(tttt--)
{
ll n,m,k;
cin>>n>>m>>k;
map<string,ll>mp;
vector<vector<string>>a(n+7,vector<string>(m+7));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
string s="";
for(int l=1;l<=k;l++)
{
char c;
cin>>c;
s+=c;
}
a[i][j]=s;
mp[s]++;
}
}
for(auto [c,b]:mp)
{
if(b==1)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==c)
{
cout<<i<<' '<<j<<'\n';
return 0;
}
}
}
}
}
}
return 0;
}
J.Temperance / 节制
题意:给定三维平面内的 \(n\) 个点,每个点的密度定义为 \(max(a,b,c)\) ,其中 \(a,b,c\) 分别为除了该点以外与该点拥有相同的 \(x,y,z\) 坐标的点的个数。对于 \(k=0,1,···,n-1\) ,求出至少要移除多少点才能使剩下来的所有点的密度都大于等于 \(k\) 。
限制条件: \(n,|x|,|y|,|z|≤10^5\)。
题解:对于一个密度为 \(k_i\) 的点 \(i\) ,不妨设与它的 \(x\) 相等的点最多,即为 \(k_i\)。那么这些点在询问的 \(k≤k_i\) 时是不会被删去的,因为它们的密度至少也会是 \(k_i\)。故 \(i\) 号点只会在 \(k>k_i\) 的时候被删掉。对于每个点,处理出它的密度,然后把它在第几天被删掉的贡献加上,就能够得到 \(ans\) 数组,然后再依次求前缀和即可,时间复杂度 \(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct node
{
ll x,y,z;
};
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n;
cin>>n;
vector<node>a(n+7);
vector<ll>dx(1e5+7,0),dy(1e5+7,0),dz(1e5+7,0),p(n+7),ans(n+7,0);
for(int i=1;i<=n;i++)
{
ll x,y,z;
cin>>x>>y>>z;
a[i]={x,y,z};
dx[x]++;dy[y]++;dz[z]++;
}
for(int i=1;i<=n;i++)
{
auto [x,y,z]=a[i];
ans[max(max(dx[x],dy[y]),dz[z])+1]++;
}
for(int i=1;i<=n;i++)
{
ans[i]+=ans[i-1];
cout<<ans[i]<<" \n"[i==n];
}
}
return 0;
}
B.The Magician / 魔术师
题意:给定了 \(n\) 张扑克牌,另外还有六种功能牌,你可能拥有其中的某些,每种最多一张。功能牌的功能分别是将三张牌变成方片、梅花、红桃、黑桃;将一张牌变为万能牌;将一张牌变成另一张牌的复制品,问最多能用这些牌打出几个同花,同花指的是五张相同花色的牌。
限制条件:给定的牌是一副扑克牌(无大小王)的子集,每种功能牌不超过一张。
题解:每种花色的牌只有不超过13张,算上所有功能牌也只能到18张,因此每种花色最多能打出3个同花。四种花色共有 \(4^4=256\) 种情况,分别枚举所有情况判断是否有可能组成同花即可。每次先统计一下每种花色在先不用功能牌的情况下组成要求的同花数量是否能剩下来牌,然后用所有剩下来的牌去填充缺少的数量即可。注意一下前四种功能牌的使用优先级是要高于后两种的,因为只对相应的花色有效。时间复杂度基本上是常数(
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
ll n;
cin>>n;
vector<ll>num(5,0);
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
if(s[1]=='D')num[1]++;
else if(s[1]=='C')num[2]++;
else if(s[1]=='H')num[3]++;
else if(s[1]=='S')num[4]++;
}
ll t[7],ans=0;
cin>>t[1]>>t[2]>>t[3]>>t[4]>>t[5]>>t[6];
for(int i=0;i<256;i++)
{
ll g[5]={0,i/64,i%64/16,i%16/4,i%4},mor=0,duo=t[5]+t[6];
bool yw[5]={0,0,0,0,0};
for(int i=1;i<=4;i++)
{
mor+=max(0ll,num[i]-g[i]*5);
}
for(int i=1;i<=4;i++)
{
if(num[i]<g[i]*5)
{
if(g[i]*5-num[i]>5)yw[i]=0;
else if(g[i]*5-num[i]==5)
{
if(mor>=5&&t[i]&&duo>=2)
{
yw[i]=1;
mor-=5;
duo-=2;
}
else yw[i]=0;
}
else if(g[i]*5-num[i]==4)
{
if(mor>=4&&t[i]&&duo>=1)
{
yw[i]=1;
mor-=4;
duo-=1;
}
else yw[i]=0;
}
else if(g[i]*5-num[i]==3)
{
if(mor>=3&&t[i])
{
yw[i]=1;
mor-=3;
}
else yw[i]=0;
}
else if(g[i]*5-num[i]==2)
{
if(mor>=2&&t[i])
{
yw[i]=1;
mor-=2;
}
else if(mor>=2&&duo>=2)
{
yw[i]=1;
mor-=2;
duo-=2;
}
else yw[i]=0;
}
else if(g[i]*5-num[i]==1)
{
if(mor>=1&&t[i])
{
yw[i]=1;
mor-=1;
}
else if(mor>=1&&duo>=1)
{
yw[i]=1;
mor-=1;
duo-=1;
}
else yw[i]=0;
}
}
else yw[i]=1;
}
bool ok=1;
for(int i=1;i<=4;i++)
{
ok&=yw[i];
}
if(ok)ans=max(ans,g[1]+g[2]+g[3]+g[4]);
}
cout<<ans<<'\n';
}
return 0;
}
E.The Chariot / 战车
题意:一种出租车的定价方案为:X米内收起步价A元;X米到X+Y米内的部分每米收B元;超出X+Y米的部分每米收C元。你可以在任意位置重新打车,要去距离为D的地方,问最少花多少钱。
限制条件:\(0<A,B,C,D,X,Y<10^{2077}\)。 (意思就是在Python的计算范围内)
题解:首先我们明确一个共识,你要用一种策略就尽可能多用,你用一会这种策略用一会那种策略是不会比只用一种策略更优的。
按照 \(D\) 的大小分成三种情况:
- \(D≤X\) ,一个 \(A\) 秒了。
- \(X<D≤X+Y\),此时可能是一个 \(AB\);或者尽量用 \(A\) ,最后接一个 \(A\) 或者 \(B\)。
注意 \(B\) 和 \(C\) 是每米的价格,和 \(A\) 不一样。 - \(D>X+Y\),此时可能是一个 \(ABC\) ;或者尽量用 \(A\) ,最后接一个 \(A\) 或者 \(B\);或者尽量用 \(AB\) ,最后一部分可以是新开一个 \(A\),那么之前的一部分 \(B\) 就可以减少到让最后一部分刚好和 \(A\) 相等;也可以是新开一个 \(AB\),注意这里的 \(B\) 也不是算满的;或者是最后一个 \(AB\)后面用 \(C\) 填满。
通过造点样例观察就可以发现这些就包括了所有情况,其实就是从 \(A,AB,ABC\) 三种策略里面一直坚持一个。然后直接用Python写或者套高精度板子就行了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct bigint {
int sign;
std::vector<int> v;
bigint() : sign(1) {}
bigint(const std::string &s) { *this = s; }
bigint(int v) {
char buf[21];
sprintf(buf, "%d", v);
*this = buf;
}
void zip(int unzip) {
if (unzip == 0) {
for (int i = 0; i < (int)v.size(); i++)
v[i] = get_pos(i * 4) + get_pos(i * 4 + 1) * 10 +
get_pos(i * 4 + 2) * 100 + get_pos(i * 4 + 3) * 1000;
} else
for (int i = (v.resize(v.size() * 4), (int)v.size() - 1), a; i >= 0; i--)
a = (i % 4 >= 2) ? v[i / 4] / 100 : v[i / 4] % 100,
v[i] = (i & 1) ? a / 10 : a % 10;
setsign(1, 1);
}
int get_pos(unsigned pos) const { return pos >= v.size() ? 0 : v[pos]; }
bigint &setsign(int newsign, int rev) {
for (int i = (int)v.size() - 1; i > 0 && v[i] == 0; i--)
v.erase(v.begin() + i);
sign = (v.size() == 0 || (v.size() == 1 && v[0] == 0))
? 1
: (rev ? newsign * sign : newsign);
return *this;
}
std::string to_str() const {
bigint b = *this;
std::string s;
for (int i = (b.zip(1), 0); i < (int)b.v.size(); ++i)
s += char(*(b.v.rbegin() + i) + '0');
return (sign < 0 ? "-" : "") + (s.empty() ? std::string("0") : s);
}
bool absless(const bigint &b) const {
if (v.size() != b.v.size()) return v.size() < b.v.size();
for (int i = (int)v.size() - 1; i >= 0; i--)
if (v[i] != b.v[i]) return v[i] < b.v[i];
return false;
}
bigint operator-() const {
bigint c = *this;
c.sign = (v.size() > 1 || v[0]) ? -c.sign : 1;
return c;
}
bigint &operator=(const std::string &s) {
if (s[0] == '-')
*this = s.substr(1);
else {
for (int i = (v.clear(), 0); i < (int)s.size(); ++i)
v.push_back(*(s.rbegin() + i) - '0');
zip(0);
}
return setsign(s[0] == '-' ? -1 : 1, sign = 1);
}
bool operator<(const bigint &b) const {
return sign != b.sign ? sign < b.sign
: (sign == 1 ? absless(b) : b.absless(*this));
}
bool operator==(const bigint &b) const { return v == b.v && sign == b.sign; }
bigint &operator+=(const bigint &b) {
if (sign != b.sign) return *this = (*this) - -b;
v.resize(std::max(v.size(), b.v.size()) + 1);
for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
carry += v[i] + b.get_pos(i);
v[i] = carry % 10000, carry /= 10000;
}
return setsign(sign, 0);
}
bigint operator+(const bigint &b) const {
bigint c = *this;
return c += b;
}
void add_mul(const bigint &b, int mul) {
v.resize(std::max(v.size(), b.v.size()) + 2);
for (int i = 0, carry = 0; i < (int)b.v.size() || carry; i++) {
carry += v[i] + b.get_pos(i) * mul;
v[i] = carry % 10000, carry /= 10000;
}
}
bigint operator-(const bigint &b) const {
if (b.v.empty() || b.v.size() == 1 && b.v[0] == 0) return *this;
if (sign != b.sign) return (*this) + -b;
if (absless(b)) return -(b - *this);
bigint c;
for (int i = 0, borrow = 0; i < (int)v.size(); i++) {
borrow += v[i] - b.get_pos(i);
c.v.push_back(borrow);
c.v.back() -= 10000 * (borrow >>= 31);
}
return c.setsign(sign, 0);
}
bigint operator*(const bigint &b) const {
if (b < *this) return b * *this;
bigint c, d = b;
for (int i = 0; i < (int)v.size(); i++, d.v.insert(d.v.begin(), 0))
c.add_mul(d, v[i]);
return c.setsign(sign * b.sign, 0);
}
bigint operator/(const bigint &b) const {
bigint c, d;
bigint e = b;
e.sign = 1;
d.v.resize(v.size());
double db =
1.0 / (b.v.back() + (b.get_pos((unsigned)b.v.size() - 2) / 1e4) +
(b.get_pos((unsigned)b.v.size() - 3) + 1) / 1e8);
for (int i = (int)v.size() - 1; i >= 0; i--) {
c.v.insert(c.v.begin(), v[i]);
int m = (int)((c.get_pos((int)e.v.size()) * 10000 +
c.get_pos((int)e.v.size() - 1)) *
db);
c = c - e * m, c.setsign(c.sign, 0), d.v[i] += m;
while (!(c < e)) c = c - e, d.v[i] += 1;
}
return d.setsign(sign * b.sign, 0);
}
bigint operator%(const bigint &b) const { return *this - *this / b * b; }
bool operator>(const bigint &b) const { return b < *this; }
bool operator<=(const bigint &b) const { return !(b < *this); }
bool operator>=(const bigint &b) const { return !(*this < b); }
bool operator!=(const bigint &b) const { return !(*this == b); }
friend std::ostream &operator<<(std::ostream &os, const bigint &b) {
os << b.to_str();
return os;
}
friend std::istream &operator>>(std::istream &is, bigint &b) {
std::string s;
is >> s;
b = s;
return is;
}
};
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
cin>>tttt;
while(tttt--)
{
bigint a,b,c,x,y,d;
cin>>a>>b>>c>>x>>y>>d;
if(d<=x)
{
cout<<a<<'\n';
continue;
}
else if(d<=x+y)
{
bigint ans=a+(d-x)*b;
if(d%x<=y)ans=min(ans,d/x*a+min(a,d%x*b));
else ans=min(ans,(d/x+1)*a);
cout<<ans<<'\n';
}
else
{
bigint ans=a+b*y+c*(d-x-y);
ans=min(ans,(d/(x+y))*(a+b*y)+d%(x+y)*c);
if(d%(x+y)>x)ans=min(ans,(d/(x+y))*(a+b*y)+a+b*(d%(x+y)-x));
else ans=min(ans,(d/(x+y))*(a+b*y)+a-b*min(d/(x+y)*y,x-d%(x+y)));
if(d%x<=y)ans=min(ans,d/x*a+min(a,d%x*b));
else ans=min(ans,(d/x+1)*a);
ans=min(ans,a*(d/x+1));
if(d%x<=y)ans=min(ans,a*(d/x)+b*(d%x));
else if(c<=b)ans=min(ans,a*(d/x)+b*y+c*(d%x-y));
else ans=min(ans,a*(d/x)+b*min(d%x,d/x*y)+c*max((bigint)0,d%x-d/x*y));
cout<<ans<<'\n';
}
}
return 0;
}
F.The Hermit / 隐士
题意:在 1~m 的正整数集里面选大小为n的子集,问每个子集最多能保留几个数使得剩下的数的gcd不等于min。所有答案求和对998244353取模。
限制条件:\(m≤10^5\)。
考虑一下一个子集如何删掉元素。如果不删这个子集的最小值,显然剩下的数的gcd和min都是不变的,等于没删,因此每次都要删掉当前的最小值。那就变成了每个子集要删掉多少次最小值,我们可以反过来考虑每个数要被删掉几次。
如果数 \(x\) 要删掉,也就是说所有的数都是 \(x\) 的倍数,这时候后面的数可能有0到 \(n-1\) 个。如果后面的数不是 \(n-1\) 个,那么前面就有一些数比 \(x\) 先删掉,显然这些数都会是 \(x\) 的因子,并且它们之间后一个都是前一个的倍数。我们记 \(f_{c,x}\) 为满足上述条件形成了 \(c\) 个数,并且最后一个数是 \(x\) 的方案数,而 \(x\)后面的数显然就是从 \(x+1\) 到 \(m\) 里面选 \(n-c\) 个,也就是\(\binom{\lfloor m/x \rfloor-1}{n-c}\)。所以我们要求的就是\(\sum_{1≤c≤n,1≤x≤m} f_{c,x}\binom{\lfloor m/x \rfloor-1}{n-c}\)。
下面我们考虑一下怎么求 \(f_{c,x}\) 。首先 \(c\) 的最大值是不会超过 \(\lfloor\log_2 10^6\rfloor=19\) 的。那么考虑每个 \(x\) 会贡献给谁,显然就是1到 \(m\) 里面 \(x\) 的倍数,也就是 \(f_{c+1,kx}+=f_{c,x}\) for k in 2~\(\lfloor m/x \rfloor\)。\(m+m/2+m/3+···+m/m\),这是经典的调和级数,时间复杂度 \(O(m\log m)\) ,再算上遍历c的 \(\log m\)次,预处理 \(f\) 数组的时间复杂度就是 \(O(m\log^2 m)\)。
然后枚举c和x遍历过去,每次还要求一个组合数,但也是 \(m/x\) 级别的数,预处理1到m的逆元以后很快就能求出来,这部分的时间复杂度证明可以见官方题解,我不会。这部分的时间复杂度是 \(O(m\log m \log \log m)\)。因此总时间复杂度为 \(O(m\log^2 m)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int M=998244353;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll tttt=1;
//cin>>tttt;
while(tttt--)
{
ll m,n;
cin>>m>>n;
vector<vector<ll>>f(20,vector<ll>(m+7,0));
vector<ll>inv(m+1,1);
for(int i=2;i<=m;i++)
{
inv[i]=(M-M/i)*inv[M%i]%M;
}
auto C=[&](ll n,ll m)
{
if(m>n)return 0ll;
ll ans=1;
for(int i=m+1;i<=n;i++)
{
ans=ans*i%M;
}
for(int i=1;i<=n-m;i++)
{
ans=ans*inv[i]%M;
}
return ans;
};
for(int i=1;i<=m;i++)f[1][i]=1;
for(int p=1;p<19;p++)
{
for(int i=1;i<=m;i++)
{
if(!f[p][i])continue;
for(int j=2*i;j<=m;j+=i)
{
f[p+1][j]=(f[p+1][j]+f[p][i])%M;
}
}
}
ll ans=0;
for(int p=1;p<=min(n,19ll);p++)
{
for(int i=1;i<=m;i++)
{
ans=(ans+f[p][i]*C(m/i-1,n-p)%M)%M;
}
}
cout<<(C(m,n)*n%M-ans+M)%M<<'\n';
}
return 0;
}
谢谢你的阅读!
CCPC2024济南个人题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
- JSOI2016R3 瞎BB题解
题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...
随机推荐
- BGP-LS原理及基本功能测试方法
BGP-LS产生的原因 BGP Link State是一种新型的收集网络拓扑信息的技术. 传统网络拓扑信息收集方式是路由器使用IGP(OSPF或IS-IS)协议收集网络拓扑信息,不同网络域中的IGP协 ...
- Redis-分布式缓存
分布式缓存 redis 是非常热门的缓存选择.但是,如果只有一个 redis 节点,那么就会面临很多问题.所以,更好的做法是搭建 redis 集群,可以使用多个节点缓存数据.多节点 redis 其实就 ...
- 小明的oj2025年3月月赛-Div2
T1 1.算法思想难度 问题类型:枚举. 错误原因:没有排序 2.改进措施 写完之后要手造数据,再检查一遍. 3.数学建模维度 复杂度计算: 排序:\(O(n\log n)\) 枚举:\(O(n)\) ...
- rust trait 熟识系列:一日一trait之Seek trait
Seek 顾名思义就是用来方便查找的trait,其内部提供了一个在字节流(stream of bytes)移动的游标(cursor),移动游标 可以改变操作字节流的位置. Seek trait 定义 ...
- react使用以及延伸
ES6方面: 关于export,import,export default使用,下面这篇博客写的不错: https://www.cnblogs.com/xiaotanke/p/7448383.html ...
- 让AI“上天”“入地” 百度打开未来世界
将大模型和生成式AI送到普通人手里,让大模型触手可得. 从ChatGPT问世至今,已经过去2年.大模型和生成式AI带给人们的,除了无限畅想,还有理想与现实的差距. 即便AI手机.AI PC.AI汽车相 ...
- 浅谈ThreadLocal----每个线程一个小书包
ThreadLocal是什么?thread是线程,local是本地的意思字面意思是线程本地.其实更通俗的理解是给每个线程设置一个缓存.这个缓存用来存储当前线程在未来的业务逻辑中需要执行到的变量.我们先 ...
- 模拟集成电路设计系列博客——4.3.2 双晶体管MOSFET-C积分器
4.3.2 双晶体管MOSFET-C积分器 MOSFET-C滤波器类似于全差分有源RC滤波器,除了电阻被等效的线性区MOS晶体管所取代.由于有源RC和MOSFET-C滤波器紧密关联,对于设计者来说,一 ...
- 芯片验证板卡设计原理图:446-基于VU440T的多核处理器多输入芯片验证板卡
446-基于VU440T的多核处理器多输入芯片验证板卡 一.板卡概述 基于XCVU440-FLGA2892的多核处理器多输入芯片验证板卡为实现网络交换芯片的验证,包括四个FMC接口.DDR ...
- Ubuntu下NVIDIA 驱动的卸载和安装
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...