ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目链接:https://codeforces.com/contest/1100
A
题意:
有两种数,一种1,一种-1,现有一个这两种数组成的数列
从数列里去掉一些数,问剩下1的个数和-1的个数的差的绝对值最大是多少
解:当把1和-1相加就可以表示 1的个数减去-1的个数了
把总和减去去掉的数的和,就表示剩下1的个数和-1的个数的差
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,k,a[200];
int main(){
cin>>n>>k;
int sum=0;
fo(i,1,n)scanf("%d",&a[i]),sum+=a[i];
// 求和过程相当于 test总数 减 information总数 (因为互为相反数)
int ans = 0;
fo(i,1,k){
int now = 0;
for(int j=i; j<=n; j+=k){
now+=a[j];
}
ans = max(ans,(int)fabs(sum-now)); // 做差相当于把关掉的任务去掉
}
cout<<ans<<endl;
return 0;
}
B
输入k个1~n的数字,当有n个不重复的数字出现时,输出1并把这n个不同数字使用掉,否则输出0,把
数字存起来
法一:
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,k,x,level[100005],cnt[100005]; // level[x]表示第x遍,cnt[x]表示x共有几个
int main(){
scanf("%d%d",&n,&k);
fo(i,1,k){
scanf("%d",&x);
if(++level[++cnt[x]]==n)putchar('1');
else putchar('0');
}
return 0;
}
法二:
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,k,x;
unordered_map<int,int> mp;
int main(){
scanf("%d%d",&n,&k);
fo(i,1,k){
scanf("%d",&x);
mp[x]++;
if(mp.size()>=n){
fo(j,1,n){
if(mp.find(j)!=mp.end()){// 查找指针
mp[j]--;
if(mp[j]==0)mp.erase(mp.find(j));
// erase(数字)是删掉全部,erase(指针)是删掉一个
}
}
putchar('1');
}else putchar('0');
}
return 0;
}
C
题意:
给定一个内圆半径R,然后外边有n个圆把内圆无缝包围起来,问内圆半径
解:
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n;
double r,ans;
int main(){
cin>>n>>r;
double t =sin(3.1415926/n);
ans = r*t/(1-t);
printf("%.7f",ans);
return 0;
}
D
E
题目都看不明白啊~~~
题意是这样的,有一些司机喜欢绕远路多收钱
于是市长就规定不能通过同一个地点两次,他需要反转一些边来实现
就是说要把一幅有环(可能有环)的图通过翻转一些边使得图变无环
反转一些边需要的人员数量不同,人员可以重复使用
也就是说 翻转3条边需要的人员数量为 3 4 5,那么总代价为5
问最少需要的代价为多少,使得图变为有向无环图,并输出要翻转的边
题解
最小化问题使用二分查找答案
判断是否是无环图使用拓扑排序,然后根据拓扑排序找出那些构成环的边进行修改
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 100005;
struct node{
int s,t;
ll cost;
}a[maxn];
int n,m,deg[maxn],top[maxn];
vector<int> G[maxn],ANS;
bool ok(ll mid, bool build){
fo(i,1,n)G[i].clear();
memset(deg,0,sizeof(deg));
// 一定要出现的边,不需要翻转
fo(i,1,m){
if(a[i].cost>mid){
G[a[i].s].push_back(a[i].t);
deg[a[i].t]++;
}
}
// topsort
queue<int> q;
vector<int> tsort; // 清空比较慢(所以不全局了)
fo(i,1,n)if(deg[i]==0)q.push(i);
while(!q.empty()){
int u = q.front();q.pop();
tsort.push_back(u);
for(int v:G[u]){
if(--deg[v]==0){
q.push(v);
}
}
}
// 构造答案
if(build){
fo(i,0,n-1){
top[tsort[i]]=i; // 点tsort[i]的拓扑序
}
fo(i,1,m){
if(a[i].cost<=mid && top[a[i].s]>top[a[i].t]){ // top序反了
ANS.push_back(i);
}
}
}
return tsort.size()==n;
}
void solve(){
ll L=0,R=1e9,mid,ans=1e9;
while(L<=R){
mid = (L+R)>>1;
if(ok(mid,0)){
ans = mid;
R = mid-1;
}else{
L = mid+1;
}
}
ok(ans,1);
printf("%lld %d\n",ans,ANS.size());
// 这个fo是错的 ANS.size()==0的时候会错
// fo(i,0,ANS.size()-1){ // 卧槽,惊了
// printf("%d%c",ANS[i],i==ANS.size()-1?'\n':' ');
// }
// 这个for是对的
for (int i = 0; i < ANS.size(); i++) {
printf("%d%c",ANS[i],i==ANS.size()-1?'\n':' ');
}
}
vector<int> ver;
int main(){
cout<<"ver.size() = "<<ver.size()<<endl;
cout<<"ver.size()-1 = "<<ver.size()-1<<endl;
scanf("%d%d",&n,&m);
fo(i,1,m){
scanf("%d%d%lld",&a[i].s,&a[i].t,&a[i].cost);
}
solve();
return 0;
}