CodeForces - 1249B2 *
每个数都有一个对应的数字p,每一天第i个人的书给pi,求书回到自己手上需要的天数。
#include<bits/stdc++.h>
#define N 200010
using namespace std;
int kds[N];
bool vis[N];
map<int,int> mp;
vector<vector<int>> v;
vector<int> vv;
void dfs(int index){
if(vis[index]) return;
vis[index]=true;
mp[index]=v.size();
vv.push_back(kds[index]);
dfs(kds[index]);
}
int main(){
int q;
cin>>q;
for(int i=0;i<q;i++){
int n;
cin>>n;
memset(kds,0,sizeof(kds));
memset(vis,false,sizeof(vis));
mp.clear();
v.clear();
for(int j=1;j<=n;j++) cin>>kds[j];
for(int j=1;j<=n;j++){
if(vis[j]) continue;
vv.clear();
dfs(j);
v.push_back(vv);
}
cout<<v[mp[1]].size();
for(int j=2;j<=n;j++) cout<<' '<<v[mp[j]].size();
putchar('\n');
}
return 0;
}
CodeForces - 1249C1
给出一个数,找出一个不小于他且可用3的次方的和表示的数(每个3的次方的系数只能是1)
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int nn=n;
int cnt=0;
while(nn!=0){
nn/=3;
cnt++;
}
int sum=0;
for(int i=cnt;i>=0;i--)
sum+=pow(3,i);
for(int i=cnt;i>=0;i--)
{
if(sum-pow(3,i)>=n)
sum-=pow(3,i);
}
cout<<sum<<endl;
}
return 0;
}
这题我试了好久都没成功,看了别人的代码我觉得我的思路是有问题的,我是想着一次成型,一次循环就排除不要的3次幂,而大佬是先把所有的3次幂加起来,最后再一个一个减去,大大降低了难度。
CodeForces - 1249C2
同上,数据变大了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll n;
scanf("%lld",&n);
ll sum=0,x=1;
while(sum<n)
{
sum+=x;
x=x*3;
}
while(x)
{
if(sum-x>=n)
sum-=x;
x=x/3;
}
printf("%lld\n",sum);
}
return 0;
}
和简单版本的思路相同,但是因为pow返回值的类型不能超int,但本题需要long long
CodeForces - 1249D1 *
给出n个区间,每个区间有左右端点(闭区间),每个区间 的覆盖定义为区间里的整数个数,问最少去掉哪几个区间可以使没所有点被区间覆盖的次数少于等于k次
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxx=2e2+10;
struct node{
int x,y;
bool operator<(const node &a)const{
if(y==a.y) return x<a.x;
else return y<a.y;
}
}p[maxx];
int a[maxx],vis[maxx];
int n,k;
int main()
{
scanf("%d%d",&n,&k);
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
a[p[i].x]++;
a[p[i].y+1]--;
}
for(int i=1;i<=200;i++) a[i]+=a[i-1];
int ans=0;
for(int j=1;j<=200;j++)
{
while(a[j]>k)
{
int tmp=0;
for(int i=1;i<=n;i++) if(p[i].x<=j&&p[i].y>=j&&(tmp==0||p[i].y>p[tmp].y)&&vis[i]==0) tmp=i;
vis[tmp]=1;
ans++;
for(int i=p[tmp].x;i<=p[tmp].y;i++) a[i]--;
}
}
cout<<ans<<endl;
for(int i=1;i<=n;i++) if(vis[i]) cout<<i<<" ";cout<<endl;
return 0;
}
求出每一个点的覆盖次数,遍历所有的点,如果它是坏点的话,就遍历目前没有删除的线段,寻找一个右区间最远的并且覆盖这个点的线段将之删除
CodeForces - 1249D2 *
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+10;
int n,k;
struct Node
{
int y;
int idx;
};
bool operator<(Node a,Node b)//排序
{
if(a.y!=b.y)
return a.y<b.y;
return a.idx<b.idx;
}
vector<Node> g[N];
vector<int> ans;
int main()
{
int x,y;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
Node p;
scanf("%d%d",&x,&y);
p.y=y;
p.idx=i;
g[x].push_back(p);
}
set<Node> s;
for(int i=1;i<N;i++)
{
while(s.size()&&(*s.begin()).y<i)//没有被覆盖的区间删除
s.erase(*s.begin());
for(int j=0;j<g[i].size();j++)//存入可覆盖区间
s.insert(g[i][j]);
while(s.size()>k)//判断该点被覆盖次数是否超过 k
{
ans.push_back((*s.rbegin()).idx);//删除的区间存下
s.erase(*s.rbegin());
}
}
printf("%d\n",ans.size());
int len=ans.size();
for(int i=0;i<len;i++)
{
printf("%d%c",ans[i],i==len-1?'\n':' ');
}
return 0;
}