比赛链接:Dashboard - Codeforces Round 883 (Div. 3) - Codeforces
目录
A. Rudolph and Cut the Rope
B. Rudolph and Tic-Tac-Toe
C. Rudolf and the Another Competition
D. Rudolph and Christmas Tree
E. Rudolf and Snowflakes
F. Rudolph and Mimic
G. Rudolf and CodeVid-23
A. Rudolph and Cut the Rope
题意:给你n个绳子高度和绳子长度,问你至少需要割掉几根绳子才能得到糖果。
思路:若绳子高度比长度长则糖果会被吊着到不了地面,所以比较绳子长度和高度大小即可。
代码:
void solve() {
int n,x,y,ans=0;
cin>>n;
FOR(1,n) {
cin>>x>>y;
ans+=(x>y);
}
cout<<ans<<endl;
}
B. Rudolph and Tic-Tac-Toe
题意:给你一个已经3*3的已经布置好的棋盘,横着连一块竖着连一块或者斜着连一块那个人就赢了,问你谁会赢。
思路:按照题意模拟即可。
代码:
void add(char c) {
if(c=='X')x++;
else if(c=='O')y++;
else if(c=='+')z++;
}
void solve() {
x=y=z=0;
for(int i=1; i<=3; i++)
for(int j=1; j<=3; j++)
cin>>a[i][j];
for(int i=1,j=1; i<=3; i++) {
if(a[i][j]==a[i][j+1]&&a[i][j+1]==a[i][j+2]) add(a[i][j]);
if(a[j][i]==a[j+1][i]&&a[j+1][i]==a[j+2][i]) add(a[j][i]);
}
if(a[1][1]==a[2][2]&&a[3][3]==a[1][1]) add(a[1][1]);
if(a[3][1]==a[2][2]&&a[3][1]==a[1][3]) add(a[1][3]);
if(x)cout<<"X"<<endl;
else if(y)cout<<"O"<<endl;
else if(z)cout<<"+"<<endl;
else cout<<"DRAW"<<endl;
}
C. Rudolf and the Another Competition
题意:给你n个m行的出题时间,比赛在第h分钟罚时结束,每做一个题的罚时会累加到后面,你是第一个人,问你的排名是多少(若有人和你并列,你的排名则在那个人的前面)。
思路:出题快的先写,排序模拟一下即可。记得开long long,该题会爆int(我已经#define int long long 了)。
struct st {
int num,t,id;
};
bool cmp(st a,st b) {
if(a.num!=b.num)return a.num>b.num;
if(a.t!=b.t)return a.t<b.t;
return a.id<b.id;
}
void solve() {
vector<st>ans;
int n,m,h,res=0;
cin>>n>>m>>h;
for(int i=1;i<=n;i++) {
vector<int>v;
for(int j=1;j<=m;j++) {
int x;
cin>>x;
v.push_back(x);
}
int sum=0,t=0,num=0;
sort(v.begin(),v.end());
for(auto x:v) {
if(sum+x>h)break;
num++,sum+=x,t+=sum;
}
ans.push_back({num,t,i});
}
sort(ans.begin(),ans.end(),cmp);
for(auto x:ans) {
res++;
if(x.id==1)break;
}
cout<<res<<endl;
}
D. Rudolph and Christmas Tree
题意:给你n个等腰三角形的底和高,还有它在坐标轴上的高度,问你最后这几个三角形的总面积是多少(可能会重叠)。
思路:若该三角形是第一个三角形或者它没和上一个三角形重叠,它对答案的贡献就为它自己的面积;若它与上一个三角形重叠了,那么未重叠部分就是梯形,这个三角形对答案的贡献为梯形面积。梯形面积为(上底+下底)*高/2,上底和高都能通过相似的比例求出来,将每个三角形的贡献求出来即可。
void solve() {
int n;
double d,h;
double ans=0;
cin>>n>>d>>h;
for(int i=1; i<=n; i++)cin>>a[i];
sort(a+1,a+n+1,greater<int>());
for(int i=1; i<=n; i++) {
if(i==1||a[i]+h<=a[i-1]) {
ans+=d*h/2;
continue;
}
double k=(a[i-1]-a[i]);//高
double dd=d*((h-k)/h);//上底
ans+=(dd+d)*k/2;
}
cout<<fixed<<setprecision(8)<<ans<<endl;
}
E. Rudolf and Snowflakes
题意:给你一个n,问你是否能够找到(1-q^k)/(1-q)(等比数列前n项和)恰好等于n,其中q,k为自定义,q>=2,k>=3。
思路:当q小于1e6时,直接预处理判断即可,而当q大于1e6时时候,若k等于4,则(1-q^4)/(1-q)>1e18,超过了n范围了,所以当q>1e6时k只可能等于3,此时只需要判断q^2+q+1=n,是否存在整数根即可(预处理会爆long long,记得开__int128)。
const int maxn = 1e6 + 5;
unordered_map<int,bool>mp;
void solve() {
int n;
cin>>n;
if(mp[n]) {
yes;
return;
}
int k=4*n-3;
int q=sqrt(k);
if(q*q==k&&n!=1&&n!=3)yes;
else no;
}
signed main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
for(int i=2; i<=maxn; i++) {
__int128 k=i*i*i;
for(__int128 j=1+i+i*i; j<=1e18; j+=k,k*=i)mp[j]=true;
}
int _;
cin >> _;
while (_--)
solve();
return 0;
}
F. Rudolph and Mimic
题意:
思路:因为模仿者不能连续超过两个阶段保持同一个值, 所以在不超过两步的时候必然会有一个值x的个数会增加,换句话说就是模仿者变成了x,所以模仿者就在这些x之中。接下来我们把值不等于x的值给去除,在不超过两步的时候又必然有个值会变化,所以在剩下来的值中,不同于原先的x的即是模仿者。
代码:
map<int,vector<int>>mp1,mp2;
int n,x,f,ff;
void sol() {
cout<<"- 0"<<endl;
for(int i=1; i<=9; i++)mp2[i].clear();//初始化
for(int i=1; i<=n; i++) cin>>x,mp2[x].push_back(i);//存储输入元素及其下标
for(int i=1; i<=9; i++) {
if(mp2[i].size()>mp1[i].size()) {
f=i;//f记录的是第一次模仿者变成了什么数字
return;
}
}
}
void sol2() {
for(int i=1; i<=n; i++) {
cin>>x;
if(x!=f)ff=i;//模仿者改变了所以和其它元素的值不同,ff记录模仿者下标。
}
}
void solve() {
f=0,ff=0;
cin>>n;
for(int i=1; i<=9; i++)mp1[i].clear();
for(int i=1; i<=n; i++)cin>>x,mp1[x].push_back(i);
while(!f) sol();
cout<<"- "<<n-(int)mp2[f].size();
n=mp2[f].size();
for(int i=1; i<=9; i++)
if(i!=f)
for(auto x:mp2[i]) cout<<" "<<x;//把其它元素排除,使得除模仿者之外,剩下元素的值一样
cout<<endl;
sol2();
while(!ff) cout<<"- 0"<<endl,sol2();
cout<<"! "<<ff<<endl;
}
G. Rudolf and CodeVid-23
题意:
思路:可以注意到n<=10,所以我们可以将二进制的字符串转换为10进制的数字,方便计算它们的贡献。设一开始的状态为a,一个药的药效为b,它的副作用为c,则a用了这个药后会变为(a&~b)|c。~为取反的意思,1变0,0变1。这是因为b中的1会使得a中相同位的1变成0(也就是治病),并且b中的0对于a没有影响,所以要用&且取反;而c中的1会使得a中相同位的0变成1(也就是副作用导致生病),并且c中的0对于a没有影响,所以要用 |。
然后将每个药需要消耗的天数作为边权,(a&~b)|c作为转移公式,跑一遍最短路即可。若dis[0]>=inf则说明跑不到0(没病的情况),输出-1;反之输出dis[0]。
代码:
int get(string s){
int n=s.size(),sum=0,now=1;
for(int i=n-1;i>=0;i--){
sum+=now*(s[i]=='1');
now*=2;
}
return sum;
}
void solve() {
mem(vis,0);
mem(dis,inf);
int n,m,now;
string s,s1,s2;
cin>>n>>m>>s;
now=get(s);
dis[now]=0;
for(int i=1;i<=m;i++){
cin>>d[i]>>s1>>s2;
a[i]=get(s1),b[i]=get(s2);
}
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,now});
while(!q.empty()){
auto k=q.top();
q.pop();
if(vis[k.second])continue;
vis[k.second]=true;
for(int i=1;i<=m;i++){
int temp1=(k.second&~a[i])|b[i];
int temp2=dis[k.second]+d[i];
if(dis[temp1]>temp2){
dis[temp1]=temp2;
q.push({temp2,temp1});
}
}
}
if(dis[0]>=inf)cout<<-1<<endl;
else cout<<dis[0]<<endl;