Dashboard - Codeforces Round #485 (Div. 2) - Codeforces
A. Infinity Gauntlet
题意:给你一个大小为6的A到B的映射,现在给出一些A中的元素,问A中剩下的元素映射之后是什么?
思路:开个map记录一下,然后模拟一下过程就OK了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =998244353;
map<string,string>mp;
map<string,bool>q;
void solve(){
ll n;cin>>n;
for(int i=1;i<=n;++i){
string s;cin>>s;
q[s]=true;
}
cout<<6-n<<'\n';//已经拿了n个,那一定剩下6-n个
for(auto w:mp){
if(q[w.first])continue;
cout<<w.second<<'\n';
}
}
int main() {
mp["purple"]="Power";
mp["green"]="Time";
mp["blue"]="Space";
mp["orange"]="Soul";
mp["red"]="Reality";
mp["yellow"]="Mind";
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
B. High School: Become Human
题意:问和
的大小关系?
思路:俩边同时取对数(任意)变成比较和
的大小关系(精度意外的不错?)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =998244353;
void solve(){
int a,b;cin>>a>>b;
double la=log(a),lb=log(b);//C++自带的以e为底的log函数
if(b*la==a*lb)cout<<"=\n";
else if(b*la<a*lb)cout<<"<\n";
else cout<<">\n";
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
C. Three displays
题意:一个序列有n个数,找到其中三个数,他们的下标满足
,并且
问,这样的最小的的和?
思路:发现是可以DP的,定义DP[i][j]为前i个数,以第i个数为结尾的长度为j的满足条件的最小答案,转移也很好转移,具体可以看代码。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+5;
const ll mod =998244353;
ll s[3005],c[3005];
ll dp[3005][4];
void solve(){
int n;cin>>n;
for(int i=1;i<=n;++i)cin>>s[i];
for(int i=1;i<=n;++i)cin>>c[i];
for(int i=0;i<=n;++i){
for(int j=0;j<=3;++j)dp[i][j]=1e18;//初始要赋值最大,因为我们有取min操作
}
for(int i=1;i<=n;++i){
dp[i][1]=c[i];//长度为1肯定是自己。
for(int j=1;j<i;++j){
if(s[i]>s[j]){
dp[i][2]=min(dp[i][2],dp[j][1]+c[i]);//长度为2从前面长度为1的答案转移
dp[i][3]=min(dp[i][3],dp[j][2]+c[i]);//长度为3从前面长度为2的答案转移
}
}
}ll ans=1e18;
for(int i=3;i<=n;++i)ans=min(ans,dp[i][3]);//找最优答案
if(ans==1e18)cout<<-1<<'\n';
else cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
D. Fair
题意:一个n个点,m条边的图(边权为 1 ),保证图是联通的,每个点都有一个类型为的物品,任意俩个点之间的距离是他们之间最短路的距离,问对于
每一个点来说,找到s个不同的点,使得他们之间的物品类型两两不同且他们到点i的距离最短
思路:发现k和s最大值不会超过100,也就是最多100个物品,那么,我们可以对与每一种类型来考虑,BFS求出每一种类型到所有点的最短距离,对于点 i ,答案就是100个类型中到i的距离最短的s个点,排个序就好了。
复杂度的话,BFS每个点只看k次,查询时有个大小为k的排序 O(nklogk)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e5+5;
const ll mod =998244353;
ll n,m,k,s;
ll a[N];
vector<ll>d[105],mp[N];
ll dp[N][105];
void solve(){
cin>>n>>m>>k>>s;
for(int i=1;i<=n;++i){
cin>>a[i];
d[a[i]].push_back(i);//每一个类型的下标
}
for(ll i=1,u,v;i<=m;++i){
cin>>u>>v;
mp[u].push_back(v);// 连个边
mp[v].push_back(u);// 双向的
}
for(int i=1;i<=n;++i){
for(int j=1;j<=k;++j)dp[i][j]=1e18;//初始化最大,有取min
}
//BFS
for(int i=1;i<=k;++i){
queue<ll>q;
for(auto u:d[i]){
q.push(u);
dp[u][i]=0;
}
while(!q.empty()){
ll g=q.front();q.pop();
for(auto v:mp[g]){
if(dp[v][i]<=dp[g][i]+1)continue;//如果我们要到的点已经搜过了就不用看了
dp[v][i]=dp[g][i]+1;
q.push(v);
}
}
}
for(int i=1;i<=n;++i){
sort(dp[i]+1,dp[i]+k+1);//排个序,因为只要前s小
ll ans=0;
for(int j=1;j<=s;++j)ans+=dp[i][j];
cout<<ans<<' ';
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
E. Petr and Permutations
题意:有一个1~n的全排列,一种操作,操作是随机选择俩个数交换顺序。
有俩个人,第一个人操作3n次,第二个人操作7n+1次
现在给出你操作完后的排序,问你是谁操作的
思路:容易发现当给出n后,这俩个人的操作数一个奇数次,另一个是偶数次,再结合奇数次操作后逆序对的变化一定是奇数,偶数次操作后逆序对的变化一定是偶数,很容易找到联系。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+5;
const ll mod =998244353;
ll tree[N],n,res;
void change(ll i,ll d){
for(;i<=n;i+=(i&-i))tree[i]+=d;
}
ll ask(ll i){
ll ans=0;
for(;i>=1;i-=(i&-i))ans+=tree[i];
return ans;
}
//上面这些是用来求逆序对的数量的
void solve(){
cin>>n;
// 当n是偶数,3n是偶数,7n+1是奇数
// 当n是奇数,3n是奇数,7n+1是偶数
for(int i=1;i<=n;++i){
ll x;cin>>x;
change(x,1);
res+=ask(n)-ask(x);
}
if((n+res)&1)cout<<"Um_nik\n";//如果是后者 那这俩个数相加一定是个奇数
else cout<<"Petr\n"; //反之,一定是个偶数
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
F. AND Graph
题意:给你m个数,数的范围是,如果其中俩个数
满足
则连一条边,问最后有多少个联通块?
思路:对于每一位进行考虑,如果一个数x可以和另一个数y连边,那么另一个数y一定在是x为1的位上为0,其他任意,那我们只要DFS每一个点连接这谁就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 5e6+5;
const ll mod =998244353;
ll n,m,x,w;
bool has[N],vis[N];
void dfs(ll x){
if(vis[x])return ;
vis[x]=true;
for(int i=0;i<n;++i){
int d=(1<<i);
if((x&d)){
dfs((x^d));
}
}
if(has[x])dfs((x^w));//如果这个点是存在的证明他还是可以搜
}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;++i){
cin>>x;has[x]=true;
}
ll limit=1ll<<n,ans=0;
w=limit-1;
for(int i=0;i<limit;++i){
if(has[i]){
if(vis[i])continue;
vis[i]=true;//i 和 (i^w)先连一条边
dfs((i^w));
ans++;//搜了几次就证明有几个联通块了
}
}
cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int _=1;//cin>>_;
while(_--){
solve();
}
return 0;
}
本人还很菜,其中可能有些错误或者不严谨的地方,请见谅。