题意:翻书,从x到y,每次翻d页,边缘不会翻过,求最小翻书次数
题解:只有三种方式,暴力就好,注意abs(x-y)

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+10;
int main(){
int t,n,x,y,d;scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&x,&y,&d);
int ans=INF;
if((y-x)%d==0) ans=min(ans,abs(y-x)/d);
int tmp=(x-1)/d+((x-1)%d!=0);
if((y-1)%d==0) ans=min(ans,tmp+(y-1)/d);
tmp=(n-x)/d+((n-x)%d!=0);
if((n-y)%d==0) ans=min(ans,tmp+(n-y)/d);
if(ans==INF) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
题意:01串,考虑交换一次两个1的位置,求最长的连续1的个数
题解:因为只能交换一次,所以记录每一个S的位置,然后讨论间隔就好,注意内部交换

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];int pre[N];
int id[N];
int main(){
int n,sum=0;scanf("%d",&n);
scanf("%s",s+1);s[0]='S',s[n+1]='S';
for(int i=0;i<=n+1;i++) if(s[i]=='S') pre[i]++;else sum++;
for(int i=1;i<=n+1;i++) pre[i]+=pre[i-1];id[1]=0;
for(int i=1;i<=n+1;i++) if(pre[i]==pre[i-1]+1) id[pre[i]]=i;
int len=pre[n+1],ans=0;
for(int i=1;i+2<=len;i++){
int num=id[i+2]-id[i]-1;
//长度是9
if(num<=sum) ans=max(ans,num);
else if(num-1==sum) ans=max(ans,sum);
}
for(int i=1;i+1<=len;i++) ans=max(ans,id[i+1]-id[i]-1);
printf("%d\n",ans);
return 0;
}
题意:m个专业,已知n个人的专业,以及技能点(有负数),要求选择一个集合,集合里面每个科目的人数相等,求最大技能点总和
题解:贪心选取,o(n),记录前缀,用ans[N]数组优化掉最外面的一维选取个数(这点。。emmmm常识。。。。)!!!!!

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+10;
vector<int>g[N];
vector<ll>gg[N];ll ans[N];
bool cmp(int a,int b) {return a>b;}
int main(){
int n,m,x,y,max_=0;scanf("%d%d",&n,&m);
int cnt=0;
for(int i=1;i<=n;i++) scanf("%d%d",&x,&y),g[x].push_back(y);
for(int i=1;i<=m;i++) sort(g[i].begin(),g[i].end(),cmp);
for(int i=1;i<=m;i++){
for(int j=0;j<g[i].size();j++){
if(j==0) gg[i].push_back(g[i][j]);
else gg[i].push_back(gg[i][j-1]+g[i][j]);
}
}
for(int i=1;i<=m;i++)for(int j=0;j<gg[i].size();j++)
if(gg[i][j]>0) ans[j+1]+=gg[i][j];
ll cmp=0;
for(int i=1;i<=n;i++) cmp=max(cmp,ans[i]);
printf("%lld\n",cmp);
return 0;
}
题意:构造题。给定n个点的最大度数,构造一个图拥有最大直径
题解:特别像高中的时候的同分异构体的构造,直接考虑度大于2的点连成串,度等于1的点加进去就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];set<int>se;
vector<pair<int,int> >g;
int main(){
int n,num=0;scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);if(a[i]==1) num++,se.insert(i);}
if(num==0){printf("YES %d\n",n-1);printf("%d\n",n-1);for(int i=1;i<n;i++) printf("%d %d\n",i,i+1);return 0;}
if(num==n){ printf("NO\n");return 0;}
set<int>tt;for(int i=1;i<=n;i++) tt.insert(i);for(auto it:se) tt.erase(it);
int t=*se.begin();auto it=tt.begin();if(tt.size()!=0) se.erase(t);
while(it!=tt.end()) {g.push_back({t,*it});a[t]--;t=*it,it++;a[t]--;}
if(num>=2) {g.push_back({t,*se.rbegin()});a[t]--,a[*se.rbegin()]--;se.erase(*se.rbegin());}
int len=g.size();it=tt.begin();
while(se.size()!=0){
while(a[*it]==0&&it!=tt.end()) it++;
if(it==tt.end()) break;
g.push_back({*it,*se.begin()});
se.erase(se.begin());a[*it]--;
}
if(se.size()!=0) {printf("NO\n");return 0;}
printf("YES %d\n",len);printf("%d\n",g.size());
for(auto it:g) printf("%d %d\n",it.first,it.second);
return 0;
}
题意:n个数的序列,一次操作将某个区间加上一个数,求最终c的个数的最大值
题解:说实话这个题当时没想清楚。。。emmmm.就觉得有地方能优化,这提示问题想不清楚的时候要多对他进行建模,从简单的模型,一步步构造出来,
记sum[i]为1~i中c的个数,cnt[i]为1-i中x的个数,那么对于[l,r]来操作,答案变为 sum[n]-sum[r]+sum[l-1]+cnt[r]-cnt[l-1],观察可发现对于一个给定的r的位置
,与其有关的仅仅是max(sum[l-1]-cnt[l-1]),这样之后就可以用o(n)的dp进行搞了。。。。说实话对这些dp还不是很熟悉。。。。一时想不到答案
题解:过的人数是个位数,打扰了
题解:codeforces 1082G. Petya and Graph(网络流,最大权闭合子图)
收获:感觉这场写完之后收获比较大的地方有以下的地方:
C题的错误示范T+优化(就是n个数,1<=a[i]<=m)这种的o(n)写法,以后不至于纠结
E题的启发吧。算是。。好像就是写一下,分析下,估计现在还达不到那个水平
G题的网络流:最大权闭合子图的相关模型和知识点
来源:https://www.cnblogs.com/vainglory/p/10097014.html
