2019 山东省省赛 题解

    科技2022-07-10  155

    A - Calandar.

    题意:给两个日期,规定每年12个月,每月30天,已知第一个日期是星期几,求第二个日期是星期几; 分析:水题。

    #include <iostream> #include <cstdio> #include <map> #include <cmath> #include <queue> #include <set> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define mp make_pair #define pb push_back #define T int T;scanf("%d",&T);while(T--) const ll mod=1e9+7; int main(){ ll y1,y,m1,m,d1,d; string s; ll ans1,ans; map<string,int> ss; string sss[5]={"Monday","Tuesday","Wednesday","Thursday","Friday"}; string sss1[5]={"Friday","Thursday","Wednesday","Tuesday","Monday"}; ss["Monday"] = 0; ss["Tuesday"] = 1; ss["Wednesday"] = 2; ss["Thursday"] = 3; ss["Friday"] = 4; T{ scanf("%lld %lld %lld", &y, &m, &d); cin >> s; scanf("%lld %lld %lld", &y1, &m1, &d1); ans = y*360ll+m*30ll+d; ans1 = y1*360ll+m1*30ll+d1; if(ans1>=ans){ ans1 = (ans1 - ans + ss[s]) % 5; cout << sss[ans1] << endl; }else{ ans1 = (ans - ans1 + 4 - ss[s]) % 5; cout << sss1[ans1] << endl; } } return 0; }

    D - Game on a Graph.

    题意:已知一个n个点,m条边的连通图,k个人,每个人有编号1或2表示队伍,按顺序每次没人删一条边,如果删去一条边之后图不连通,则该队输,输出赢的队伍的编号。

    分析:n个点要连通至少n-1条边,所以可以删去m-n+1条边。取余人数即可

    #include <iostream> #include <cstdio> #include <map> #include <cmath> #include <queue> #include <set> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define mp make_pair #define pb push_back #define T int T;scanf("%d",&T);while(T--) const ll mod=1e9+7; int main(){ int k,n,m; int u,v; int ans; string s; T{ scanf("%d", &k); cin >> s; scanf("%d %d", &n, &m); for(int i = 0; i < m; i ++) scanf("%d %d", &u, &v); ans =(m-n+1) % k; if(s[ans]=='1') cout << 2 << endl; else cout << 1 << endl; } return 0; }

    F - Stones in the Bucket.

    题意:n堆石头,每堆a[i]个,每次可以拿去任意一堆的一个石头,或者把任意一堆的一个石头放到另一堆,求最少几次操作后使得每堆石头数相等。 分析:先求平均值,分别求出比平均值大的和小的石头数的和,取大值。

    #include <iostream> #include <cstdio> #include <map> #include <cmath> #include <queue> #include <set> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define mp make_pair #define pb push_back #define T int T;scanf("%d",&T);while(T--) const ll mod=1e9+7; int a[1000005]; int main(){ int n; ll sum; ll ans1,ans2; ll ave; T{ ans1 = ans2 = sum = 0; scanf("%d", &n); for(int i = 1; i <= n; i ++){ scanf("%d", a+i); sum += a[i]; } ave = sum/n; for(int i = 1; i <= n; i ++){ if(a[i]>=ave) ans1 += a[i]-ave; else ans2 += ave-a[i]; } printf("%lld\n", max(ans1,ans2)); } return 0; }

    L - Median.

    题意:n个数,m个关系,接下来m行,每行一个u和v表示第u个数大于第v个数,输出n个数,1表示当前位置的数可能为中位数,0表示不可能。

    分析:建图,出现环就全为0. 否则就求出每个点的父亲和儿子个数,两周都小于等于n/2就可能为中位数,输出种没有出现过的数也可能为中位数.

    #include <iostream> #include <cstdio> #include <map> #include <cmath> #include <queue> #include <set> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define mp make_pair #define pb push_back #define T int T;scanf("%d",&T);while(T--) const ll mod=1e9+7; int n,m; vector<int> g1[105]; vector<int> g2[105]; int child[105]; int father[105]; int in[105]; int vis1[105]; int vis[105]; int is(){ queue<int> q; for(int i = 1; i <= n; i ++){ if(in[i]==0 && vis1[i]){ q.push(i); } } while(!q.empty()){ int u = q.front(); q.pop(); if(vis[u]) continue; vis[u] = 1; for(auto i : g1[u]){ in[i]--; if(in[i]==0){ q.push(i); } } } for(int i = 1; i <= n; i ++){ if(vis1[i] && vis[i]==0){ return 1; } } return 0; } int dfs1(int u){ if(vis[u]) return 0; vis[u] = 1; int sum = 1; for(auto i : g1[u]){ sum += dfs1(i); } return sum; } int dfs2(int u){ if(vis[u]) return 0; vis[u] = 1; int sum = 1; for(auto i : g2[u]){ sum += dfs2(i); } return sum; } int main(){ T{ scanf("%d %d", &n, &m); for(int i = 1; i <= n; i ++){ g1[i].clear(); g2[i].clear(); vis[i] = 0; vis1[i] = 0; in[i] = 0; father[i] = 0; child[i] = 0; } for(int i = 0; i < m; i ++){ int u,v; scanf("%d %d", &u, &v); in[v] ++; vis1[v] = vis1[u] = 1; g1[u].push_back(v); g2[v].push_back(u); } if(is()){ for(int i = 1; i <= n; i ++) printf("0"); puts(""); continue; } for(int i = 1; i <= n; i ++){ for(int j = 1; j <= n; j ++){ vis[j] = 0; } child[i] = dfs1(i) - 1; for(int j = 1; j <= n; j ++){ vis[j] = 0; } father[i] = dfs2(i) - 1; // printf("%d %d\n", child[i], father[i]); } for(int i = 1; i <= n; i ++){ // printf("%d %d\n", child[i], father[i]); if(!vis1[i] || father[i]<=n/2 && child[i]<=n/2) printf("1"); else printf("0"); } puts(""); } return 0; }

    M - Sekiro.

    题意:已知n和k,每次n/2向上取整,求k次后n是多少。 分析:n最后必然为1.

    #include <iostream> #include <cstdio> #include <map> #include <cmath> #include <queue> #include <set> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define mp make_pair #define pb push_back #define T int T;scanf("%d",&T);while(T--) const ll mod=1e9+7; int main(){ T{ int n,k; scanf("%d %d", &n, &k); if(n==0){ printf("0\n"); continue; } for(int i = 1; i <= k; i ++){ n = ceil(n*1.0/2); if(n==1) break; } printf("%d\n", n); } return 0; }
    Processed: 0.016, SQL: 8