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\)

\[ 对所有的数分解质因数,并存入相应的数时有效的数组(从大到小排序)为 \]

\[2:2,2,4,4 \]

\[3:27,9,3,3 \]

\[5:5\quad\quad\quad \]

\(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编辑  收藏  举报

导航