GYM 101875 2018 USP-ICMC

週末的一次組隊訓練,讓我再次感覺到自己的菜

題目鏈接

Problem A

題意:求最大生成樹的權值和

題解:可以證明的是,我們每一個人都向接下來的第k個人連邊,剩下的連第k-1個人,這樣得到的邊權和一定是最大的

C++版本一

#include<bits/stdc++.h>
using namespace std;
long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    long long n,k,ans;
    cin>>n>>k;
    long long a=gcd(n,k);
    if(a!=1) ans=(n-a)*k+(a-1)*(k-1);
    else ans=(n-1)*k;
    cout<<ans<<endl;
    return 0;
}

Problem B

題意:給你一串長度爲n的數,這個數可以將後面的數挪到前面來,如果沒有小於最開始的那個數的話就輸出YES,否則輸出NO

題解:如果後面有數字小於第一個數的話就肯定是NO了,這題的坑點就是如果前面很長一串都相同但是後面有一個比前面相同位置的數小的話也要輸出NO,因爲n是5e5,我們不可能檢查每一個串,其實對於這個字符串,我們可以求出這個數的最小表示法的答案,如果這個字符串的最小表示法的第一個字符不是第一個的話就是NO了

C++版本一

#include<bits/stdc++.h>
using namespace std;
int n;
string s,ss;
int main()
{
    cin>>n>>s;
    int a,b;
    for(int i=0,j=1,k=0;i<n&&j<n&&k<n;){
        int t=s[(i+k)%n]-s[(j+k)%n];
        if(t==0)k++;
        else{
            if(t>0) i+=(k+1);
            else j+=(k+1);
            k=0;    
        }
        if(i==j) j++;
        a=i;b=j;
    }
    int tt= min(a,b);
    for(int i=tt; i<tt+n; i++)
        ss+=s[i%n];
    for(int i=0; i<n; i++)
        if(ss[i]<s[i]){
            cout<<"No"<<endl;
            return 0;
        }
    cout<<"Yes"<<endl;
    return 0;
}

Problem C

題意:

題解:

C++版本一

/*
*@Author:   Agnel-Cynthia
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
#include<unordered_map>
//#define DEBUG
#define RI register int
//#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1e3+10;
const int M=1e6+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
//int t,n,m,k,p,l,r,u,v;


bool f[M];
ll p[M];
int tot = 0;
std::vector<int> v;
bool vis[3003][1003];
ll dp[3003][1003];
unordered_map<ll, ll> mp;
void init()
{
    f[0] = f[1] = 1;
    for(int i = 2; i < M; i++)
    {
        if(!f[i]) p[tot++] = i;
        for(int  j = 0; j < tot && i * p[j] < M ; j ++)
        {
            f[i * p[j]] = 1;
            if(i % p[j] == 0) break;

        }
    }

}

void add(ll &a, ll b)
{
    a += b;
    while(a >= MOD) a-=MOD;
}

void gao(ll x)
{
    for(int i = 0; i < tot && p[i] * p[i] <= x ; i++)
    {
        if(x % p[i] == 0)
        {
            int cnt = 0;
            while(x % p[i] == 0) x /= p[i],cnt ++;
            mp[p[i]] += cnt;
        }
    }
    if(x > 1) mp[x] ++;
}



long long solves(int pos,int need)
{
    if( pos == v.size()) return need == 1;
    if(vis[pos][need]) return dp[pos][need] ;
    vis[pos][need] = 1;
    for(int  i = 0; i <= v[pos]; i++)
    {
        if(need % (i + 1 ) == 0)
        {
            add(dp[pos][need], sovles(pos + 1, need / (i+1 )));
        }
    }
    return dp[pos][need];
}
int main()
{
#ifdef DEBUG
    freopen("input.in", "r", stdin);
    //freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){

    int b, n;
    init();
    scanf("%d %d",&b,&n);
    ll x;
    for(int  i = 1; i <= n ; i++)
    {
        scanf("%lld",&x);
        gao(x);
    }
    for(auto k : mp)
    {
        v.push_back(k.second);
    }
    printf("%lld\n",solves(0,b));
    //cout << "Hello world!" << endl;
    return 0;

//#ifdef DEBUG
//   printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
//#endif

}

Problem D

題意:我們最多可以走n步,每一步可以走上下左右,問你從起點走到終點有多少種方法

題解:最小步數移動到目標後,其他正好到達目標點的步數爲當前最小步數加2的倍數。

C++版本一

/*
*@Author:   Agnel-Cynthia
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
//int t,n,m,k,p,l,r,u,v;
int main()
{
#ifdef DEBUG
    //freopen("input.in", "r", stdin);
    //freopen("output.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //scanf("%d",&t);
    //while(t--){

    ll n, x1, y1, x2, y2;
    cin >> n >> x1 >> y1 >> x2 >> y2;
    ll sum1 = abs(y2 - y1) + abs(x2 - x1);
    ll sum = n - sum1;
    if(x1 == x2 && y1 == y2) cout << n/2 << endl;
    else if(sum < 0) cout << 0 << endl;
    else cout << sum/2 + 1 << endl;




#ifdef DEBUG
    printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

Problem E

題意:給你一個長度爲n的01串,0表示當天不需要工作,1表示當天需要工作,我初始時有體力值爲k,如果連續工作時,我第一天需要耗費的體力值爲1,第二天需要耗費的體力值爲2,第三天許喲啊耗費的體力值爲3,,,以此類推,問我們現在需要從這個01串中最少改變多少個1爲0使得我們k個體力值夠用

題解:DP

C++版本一

/*
*@Author:   Agnel-Cynthia
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m = 0,k,p = 1,l,r,u,v;
bool checkmin(int &a, int b){return b < a ? a =  b,true:false;}
char str[N];
int f[2][N][N],minn[N][N];
int main()
{
    scanf("%d%d",&n,&v);
    scanf("%s",str+1);
    f[m][0][0] = 0;
    for(int i = 1; i<= n; i++)
    {
        for(int j = 0; j <= i; j++)
        {
            for(int k = 0; k <= i; k++ )
            {
                if(str[i] == '0')
                {
                    if(k == 0)
                    {
                        f[p][j][0] = minn[i-1][j];
                    }
                    else f[p][j][k] = 0x3f3f3f3f;
                }
                else
                {
                    f[p][j][k] =  0x3f3f3f3f;
                    if(j && (k == 0)) checkmin(f[p][j][k],minn[i-1][j-1]);
                    if(k) checkmin(f[p][j][k],f[m][j][k-1]+k);
                }
            }
            minn[i][j] =  0x3f3f3f3f;
            for(int  k = 0; k  <= i; k++)
                checkmin(minn[i][j],f[p][j][k]);
        }
        swap(m,p);
    }
    int ans = INT_MAX;
    for(int j = 0; j <= n; ++j)
        for(int k = 0; k <= n; ++k)
        {
            if(f[m][j][k] <= v)
                checkmin(ans,j);
        }

    printf("%d\n",ans);

    return 0;
}

Problem F

題意:有n個人,每個人如果有喜歡的數,那麼他就只喜歡這些數,如果他有討厭的數,那麼他就喜歡除了這個數外的任何數,求有多少個數是這n個人都喜歡的

題解:map記錄一下就行,如果沒有隻喜歡某一些數的人的話,我們就輸出1e8-(所有人討厭的數即可)

C++版本一

/*
*@Author:   Agnel-Cynthia
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000+10;
const int M=100000+10;
const int MOD=1e9+7;
const ll maxn = 1000000000000000000;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
//int t,n,m,k,p,l,r,u,v;
map<ll,ll>mp;
map<ll,ll>mp2;
int main()
{
#ifdef DEBUG
    //freopen("input.in", "r", stdin);
    //freopen("output.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    ll n;
    int op = 0;
    cin >> n;
    ll ans = 0;
    for(ll i = 0; i < n; i++)
    {
        ll k;
        cin >> k;
        ll m;
        cin >> m;

        for(ll i = 0; i < m; i++)
        {
            ll x;
            cin >> x;
            if(k == 1)
                mp[x]++;
            if(k == 2) mp2[x]++;
        }
        if(k == 1) op ++;
        if(k == 2) ans ++;
    }
    map<ll,ll>::iterator it;
    ll sum = 0;
    for(it = mp.begin(); it != mp.end(); it++)
    {
        it -> second += ans ;
       // cout << it -> second << endl;
        // if(it -> second == n) sum++;
    }
    for(it = mp2.begin(); it != mp2.end() ; it++)
    {
        mp[it->first] -= it->second;
    }
    for(it = mp.begin(); it != mp.end(); it++)
    {
        // it -> second += ans ;
        if(it -> second == n) sum++;
    }
    if(op == 0)
       cout << (ll)(maxn - mp.size()) << endl;
    else
    cout << sum << endl;



#ifdef DEBUG
    printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

Problem G

題意:在一條直線上有n輛車,每輛車都有自己的位置和速度,如果後面一輛車撞上前面一輛車時,後面一輛車的速度會變得和前面一輛車一樣,問你什麼時候不可能有車子相撞

題解:們先將車按照pos的順序從小到大排序,定義第一輛車爲1,從n到1掃一遍,如果在第i個位置的車的速度小於我當前車的速度的話,我當前位置的的車的速度是一定會變成第i個位置的速度,否則的話,我當前位置的車是一定會被撞的,計算出被第i輛車撞的時間保存最大值即可

C++版本一

#include <bits/stdc++.h>
using namespace std;
int n;
struct node
{
    int s,v;
}a[100005];
bool cmp(node a,node b)
{
    return a.s<b.s;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].s,&a[i].v);
    }
    sort(a+1,a+1+n,cmp);
    int minn=n;
    double ans=0;
    for(int i=n-1;i>=0;i--){
        if(a[i].v<=a[minn].v) minn=i;
        else ans=max(ans,(double)(a[minn].s-a[i].s)/(a[i].v-a[minn].v));
    }
    printf("%.5f\n",ans);
    return 0;
}

Problem H

題意:有一個密碼箱,他有n個數字齒輪,每個齒輪是可以被轉動的,有兩個人玩起了這個遊戲,現在有以下的遊戲規則

題解:

C++版本一

在這裏插入代碼片

Problem I

題意:有一個遊戲,現在一共有n個人,給出n個關係,如果第i個人去的話,第a[i]個人也去

題解:若點y是x的祖先,則y肯定回來。一次dfs確定每個點覆蓋的區間,若點x的dfs序在y的覆蓋區間內,則y肯定會來。

C++版本一

/*
*@Author:   Agnel-Cynthia
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
//#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
//int t,n,m,k,p,l,r,u,v;
struct node
{
    int l,r;
} S[M];
int a[M];
vector<int> b[M];
int cnt;
dfs (int x)
{
    S[x].l = ++cnt;//處理
    for(int i = 0; i < b[x].size(); i++) dfs(b[x][i]);//一個人每一個好朋友同等級處理
    S[x].r = cnt;
}
int main()
{
#ifdef DEBUG
    freopen("input.in", "r", stdin);
    //freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    int n, q;
    // cin >> n >> q;
    scanf("%d%d",&n,&q);
    for(int  i  = 0; i < n; i++)
    {
        int x;
        // cin >> x;
        scanf("%d",&x);
        if(x == -1) continue ;
        //b[x][i] = i;
        
        //存入好朋友
        b[x].push_back(i);
        a[i] ++;
    }
    //從根出發,預處理下朋友左右
    for(int  i = 0; i < n; i++) if(!a[i]) dfs(i);

    while(q--)
    {
        int u, v;
        //cin >> u >> v;
        scanf("%d%d",&u,&v);
        if((S[v].l <= S[u].l && S[v].r >= S[u].r) == 1)
            puts("Yes");
        else
            puts("No");
    }
#ifdef DEBUG
    printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

Problem J

題意:

題解:

C++版本一

在這裏插入代碼片

Problem K

題意:

題解:

C++版本一

在這裏插入代碼片

Problem L

題意:有一個n個點的樹,小明從起點出發,問他最多可以經過多少點,每個點不能經過兩次

題解:從起點bfs一遍即可

C++版本一

#include <bits/stdc++.h>
using namespace std;
int ans=1;
vector<int>a[100005];
struct node{
    int st,de;
} b;
int vis[100005];
queue<node>e;
void bfs(int x){
    memset(vis,0,sizeof(vis));
    vis[x]=1;
    b.st=x;
    b.de=1;
    e.push(b);
    while(!e.empty()){
        e.pop();
        ans=max(ans,b.de);
        int s=b.st;
        int t=a[s].size();
        b.de++;
        for(int i=0; i<t; i++){
            if(!vis[a[s][i]]){
                vis[a[s][i]]=1;
                b.st=a[s][i];
                e.push(b);
            }
        }
        b=e.front();
    }
    return ;
}
int main()
{
    int n,x;
    cin>>n>>x;
    for(int i=1; i<n; i++){
        int c,d;
        cin>>c>>d;
        a[c].push_back(d);
        a[d].push_back(c);
    }
    bfs(x);
    cout<<ans<<endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章