2024 (ICPC) Jiangxi Provincial Contest -- Official Contest
L. Campus
1.首先考虑时间复杂度,因为最多只会有2*k的时间点,所以我们采取的策略是,对这每个时刻,判断有多少扇门是开的,并且考虑这些门到其他点的最短路之和。
2.输入完数据以后,使用dijkstra算法对每一个可以开的门,跑这个门到其他点的最短路,然后,去遍历时间1-t,对于每个时刻,检查哪些门是开的,计算这些门到每个游客的所在点的最短路之和即可。
/** - swj -
*
/>_____フ
| _ _|
/`ミ _x ノ
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
**/
#include <bits/stdc++.h>
using namespace std;
using i64=long long;
struct DIJ{
using i64=long long;
using pii=pair<i64,i64>;
vector<i64>dis;//存点到点的最小距离
vector<vector<pii> >G;//存起点和终点的编号,边权
DIJ() {}//防止默认状态报错,类似vector<int>a,
//为dijkstra初始化
DIJ(int n)
{
dis.assign(n+1,1e18);//把所有元素设置为1e18
G.resize(n+1);//把G的大小设置为n+1
}
void add(int u,int v,int w){
G[u].emplace_back(v,w);//u v为点,w为边权
}
//堆优化版的dijkstra
void dijkstra(int s) {
priority_queue<pii> que;
dis[s] = 0;
que.push({0, s});
while (!que.empty()) {
auto p = que.top();
que.pop();
int u = p.second;
if (dis[u] < p.first) continue;
for (auto [v, w] : G[u]) {
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
que.push({ -dis[v], v});
}
}
}
}
};
int main()
{
ios::sync_with_stdio(false),cin.tie(0);
int n,m,k,t;
cin>>n>>m>>k>>t;//n个点,k个点可以开门,m个点编号和边权,t时间
vector<int>a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<DIJ>dij(k,n);//初始化大小为k,每个元素为n,等价于开二维数组存地图
vector<array<int,3> >door(k);
for(auto &[p,l,r]:door){
cin>>p>>l>>r;//编号,开始时间,截止时间
}
for(int i=0;i<m;i++)
{
int u,v,w;
cin>>u>>v>>w;
for(int j=0;j<k;j++)
{
dij[j].add(u,v,w);//放点和边权,无向图
dij[j].add(v,u,w);
}
}
for(int i=0;i<k;i++)
{
dij[i].dijkstra(door[i][0]);//对每个可以开门的点,跑最短路,存这个点到其他点的最短距离。
}
vector<i64>dis;
//我们在跑完每个可以开的门到其他点的最短距离以后,先跳过函数来看代码
//我们遍历1-t时刻,每一个时刻,遍历1-k个门,检查哪个门是开的
//对于1-k个门,我们利用二进制的01来代表开和关
//-------------检查和返回答案的函数-------------------------------
auto res=[&](int x)->i64{//x相当于一个二进制数,位置上的01记录状态开门或关门
if(!x) return -1;//相当于每个位置都是0,
vector<i64>(n+1,1e18).swap(dis);//把dis数组设为n+1个1e18
for(int i=0;i<k;i++)
{
if(x>>i&1){//二进制检查,1和0分别对应这个门是不是开的,如果是1
for(int j=1;j<=n;j++) dis[j]=min(dis[j],dij[i].dis[j]);//j为游客点,游客点在这些门找最短距离
}
}
i64 res=0;
for(int i=1;i<=n;i++) res+=a[i]*dis[i];
return res;
};
//-------------------------------------------------------------
unordered_map<int,i64>ans;
for(int i=1;i<=t;i++)//遍历每个时刻
{
int mask=0;
for(int j=0;j<k;j++){//检查这个时刻,开的门有几个
auto &[p,l,r]=door[j];
if(l<=i&&i<=r) mask|=1<<j;//门是开的把第j位为设为1,j对应的是位置
}
//cout<<mask<<endl;
if(!ans.count(mask)) ans[mask]=res(mask);//重复状态直接输出结果,不再跑res,优化时间
cout<<ans[mask]<<endl;
}
}
D. Magic LCM
\(1.当我们在模拟样例1时,我们发现当最后为1,2, 2, 10 ,20时和最大\)
\(模拟样例3时,我们发现当最后为,1,1,6,6,36,540时和是最大\)
\(样例2无需修改加起来就是最大的。\)
\(2.我们发现,最后的序列每一个数都是后面的质因子,那么本质上,求最大的和,就是\)
\(移动这些质因子幂数(比如2^2,3^2)到其他数相乘,而一个质因子幂数可以移动到另一个数\)
\(的条件是,它们之间有不同的质因子。\)
\(3.我们使用一个二维数组,每行存的是对应质因子的幂数,那么不同行的相同位置,其实\)
\(就\color{red}{确保了,有不同质因子的这个条件},\)\(举个例子:样例3\)
\(4.那么对应的位置相乘起来,便是每个数的最优贡献。但是还要注意,假如6个数,质因子对应的幂数最多有4个,那么剩余两个数最后就是1。\)
总结:对这个几个数分解质因数--->存入对应的质因数的幂数--->排序后对应位置相乘--->加上剩余的1--->过程和结果的取模
/** - swj -
*
/>_____フ
| _ _|
/`ミ _x ノ
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
**/
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
#define ull unsigned long long
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
#define mod 998244353
int n;
bool vis[1010];
vector<int>pri;//放1000以内的质数,大于1000的质数直接加到结果就行,因为最大数1e6。
void olas()//线性筛素数法
{
for(int i=2;i<=1005;i++)
{
if(!vis[i]) pri.push_back(i);
for(auto v:pri)
{
if(i*v>1005) break;
vis[i*v]=1;
if(i%v==0) break;
}
}
}
vector<int>v[1000010];//存每种质数对应的数比如质因数2 存4 8 16 质因数3存3 9 27
set<int>se;//存共出现了多少种质数,方便后续的遍历
void get(int x)//用来把每个数分解
{
for(auto t:pri)
{
if(x<t) break;
if(x%t==0) {
int temp=1;
while(x%t==0){
temp*=t;
x/=t;
}
v[t].push_back(temp);//存质因子对应次幂的数
se.insert(t);
}
}
//大于1000的质数直接放进来就可以
if(x>1){
v[x].push_back(x);
se.insert(x);
}
}
void solve()
{
cin>>n;
for(int i=0;i<n;i++)
{
int x; cin>>x;
get(x);
}
int maxx=0,mk=0;//maxx是存质因数对应数数组里的最大长度,mk标记最大长度质因数
for(auto i:se){//寻找maxx与mk
if((int)v[i].size()>maxx) maxx=v[i].size(),mk=i;
sort(v[i].begin(),v[i].end(),greater<int>());//从大到小排序
}
for(auto i:se)
{
if(i==mk) continue;//把其他可以加的质因数幂次数加到这个数组里,所以这个数组不操作
for(int j=0;j<v[i].size();j++)
{
v[mk][j]=v[mk][j]*v[i][j]%mod;//对应位置相乘比如27 9 3 3
} // 和4 2 4 4
}
int ans=n-maxx;//质数因子移动的过程结束后,n-maxx个数是1
for(auto t:v[mk]) ans=(ans+t)%mod;//这里不是+= 是=
for(auto t:se) v[t].clear();
se.clear();
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
int t=1; cin>>t;
olas();
while(t--)
{
solve();
}
}
C. Liar
最多可以有n-1个人说的是实话,因为1个说假话的人的这个数据可能可以直接弥补n-1个人和s的差值
/** - swj -
*
/>_____フ
| _ _|
/`ミ _x ノ
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
**/
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
#define ull unsigned long long
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
#define mod 998244353
signed main()
{
int n,s; cin>>n>>s;
int sum=0;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
sum+=x;
}
if(sum==s) cout<<n;
else cout<<n-1;
}
G. Multiples of 5
一个数是不是5的倍数,只取决于最后一位,11的任意次方的最后一位为1,每个进制位上的数字,实际上代表的是最后一位有多少个1,那么只需要计算出所有位置上加起来的数字和是不是5的倍数即可,注意A代表的是10
/** - swj -
*
/>_____フ
| _ _|
/`ミ _x ノ
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
**/
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
#define ull unsigned long long
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
#define mod 998244353
void solve()
{
int n; cin>>n;
int sum=0;
for(int i=0;i<n;i++)
{
int a;
string b;
cin>>a>>b;
int a1,b1;
if(b=="A") b1=10;
else b1=stoi(b);
sum+=a*b1;
}
if(sum%5==0) cout<<"Yes";
else cout<<"No";
cout<<endl;
}
signed main()
{
int t=1; cin>>t;
while(t--)
{
solve();
}
}
Magic Mahjong
1.十三orphans就是:取满对应的13个,剩余一个也来自这十三种的一种,那么使用map标记,大小对应13,并且有一个元素的数量是2即可
2.七对就是:对应的种类中,每种取2张,取7种即可
/** - swj -
*
/>_____フ
| _ _|
/`ミ _x ノ
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
**/
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
#define all(v) v.begin(),v.end()
#define ull unsigned long long
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
#define mod 998244353
void solve()
{
map<string,int>fi;
vector<string>v={"1z","2z","3z","4z","5z","6z","7z",
"1p","9p","1s","9s","1m","9m"
};
for(auto t:v){
fi[t]=1;
}
vector<string>ve;
string s; cin>>s;
for(int i=0;i<s.size();i+=2)
{
string sb;
sb+=s[i];
sb+=s[i+1];
ve.push_back(sb);
}
map<string,int>mp;
for(auto t:ve) mp[t]++;
int flag=0;
if(mp.size()==13){
for(auto t:mp){
if(fi[t.x]==0){
cout<<"Otherwise";
flag=1;
break;
}
}
if(!flag) cout<<"Thirteen Orphans";
}else
if(mp.size()==7)
{
for(auto t:mp){
if(t.y!=2){
cout<<"Otherwise";
return ;
}
}
cout<<"7 Pairs";
}
else cout<<"Otherwise";
cout<<endl;
}
signed main()
{
int t=1; cin>>t;
while(t--)
{
solve();
}
}
posted on 2024-07-31 20:55 swj2529411658 阅读(50) 评论(0) 编辑 收藏 举报