题目链接:https://codeforces.com/contest/1374
这一套手速还行,但是难一点的题就不会了。最后看题解补了两题,算半AK了吧~
程序开头,后面不再重复
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define ROF(i,l,r) for(int i=l;i>=r;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define r(x) read(x)
#define rr(x,y) read(x);read(y)
#define rrr(x,y,z) read(x);read(y);read(z)
#define sss(str) scanf("%s",str+1)
#define ssf(x) scanf("%lf",&x)
#define aLL(x) x.begin(),x.end()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> pt;
const int N=2e5+5;
const int M=2e3+5;
const int INF=2e9;
const int sz=15;
const int mod=1e9+7;
const double eps = 1e-8;
const double pi= acos(-1);
template<class T>
inline void read(T &x)
{
char c;x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
不解释
int main()
{
int t;
r(t);
while(t--){
int a,b,c;
rrr(a,b,c);
int k=c/a;
m=c%a;
if(b<=m){
cout<<k*a+b<<endl;
}
else{
cout<<(k-1)*a+b<<endl;
}
}
return 0;
}
变小只能靠除以6,如果n不是只含有因数2和3的数,那肯定不行。其次其因数2的个数还不能多于因数3的个数,否则2就多于了除不尽。
int main()
{
int t;
r(t);
while(t--){
int a;
r(a);
n=m=0;
while(a%2==0){
a/=2;
n++;
}
while(a%3==0){
a/=3;
m++;
}
if(a!=1||n>m){
cout<<-1<<endl;
continue;
}
cout<<(m-n)+m<<endl;
}
return 0;
}
类似于括号匹配,只不过把不能匹配的都留下,最后 栈的大小/2 即为答案
int n,m;
char str[N];
int f[N];
int main()
{
int t;
r(t);
while(t--){
r(n);
sss(str);
stack<char> s;
FOR(i,1,n){
if(str[i]=='(') s.push(str[i]);
else{
if(s.size()&&s.top()=='('){
s.pop();
}
else{
s.push(str[i]);
}
}
}
cout<<s.size()/2<<endl;
}
return 0;
}
这题有点意思,是一个周期一样的问题
我们算出所有的 (k - ai%k) 并统计其个数
拿样例1举例 ,统计结果为 剩了2个2,1个1,1个0
依题意知,起点就是0,两个操作每次都会+1,所以+1就是1步。最后的规律就是对统计结果取max,有相同的还要去最大值,出现次数最多的决定了要经历多少周期,最后的最大值,决定终点。
int n,m;
char str[N];
int f[N];
int main()
{
int t;
r(t);
while(t--){
rr(n,m);
map<int,int> mm;
int maxx=0,num=0;
FOR(i,1,n){
r(f[i]);
int now=(m-f[i]%m)%m;
if(now==0) continue;
mm[now]++;
if(maxx<mm[now]){
maxx=mm[now];
num=now;
}
else if(maxx==mm[now]){
if(num<now){
num=now;
}
}
}
LL ans=1ll*(maxx-1)*m+num+1;
if(maxx==0&&num==0) ans=0;
cout<<ans<<endl;
}
return 0;
}
贪心即可,先将书分门别类并从小到大排序。一共只有2种取法,要么选择1本(1,1),要么选择1本(1,0)和1本(0,1)。哪种小选哪个就完了。
int n,m;
char str[N];
int f[N];
int main()
{
rr(n,m);
vector<int> v1,v2,v3;
FOR(i,1,n){
int a,b,c;
rrr(a,b,c);
if(b&&c){
v1.pb(a);
}
else if(b){
v2.pb(a);
}
else if(c){
v3.pb(a);
}
}
if(v1.size()+min(v2.size(),v3.size())<m){
cout<<-1<<endl;
return 0;
}
sort(aLL(v1));
sort(aLL(v2));
sort(aLL(v3));
int a=0,b=0,c=0;
LL ans=0;
while(m--){
int cost1=INF,cost2=INF;
if(a<v1.size()){
cost1=v1[a];
}
if(b<v2.size()&&c<v3.size()){
cost2=v2[b]+v3[c];
}
if(cost1<cost2){
a++;
ans+=cost1;
}
else{
b++;
c++;
ans+=cost2;
}
}
cout<<ans<<endl;
return 0;
}
比E1多了一个书本数的限制,范围也扩大了。
同样还是先分类排序,我们在此基础上再求前缀和
假如选了t本(1,1),那么一定选了k-t本(1,0)和(0,1)。
t + 2 ∗ ( k − t ) < = m , 故 t > = 2 k − m 。 而 t < = v [ 0 ] . s i z e ( ) , 所 以 t 的 范 围 已 经 定 了 。 t+2*(k-t)<=m ,故t>=2k-m。而t<=v[0].size(),所以t的范围已经定了。 t+2∗(k−t)<=m,故t>=2k−m。而t<=v[0].size(),所以t的范围已经定了。
我们遍历t,二分查找合适的最大值。详见代码~复杂度 O ( l o g ( l o g ( n ) ) ) O(log(log(n))) O(log(log(n)))
int n,m;
char str[N];
int f[N];
vector<pt> v[4];
vector<int> sm[4];
set<int> ans;
int main()
{
int k;
rrr(n,m,k);
FOR(i,1,n){
int a,b,c;
rrr(a,b,c);
v[3-(2*b+c)].pb(mp(a,i));
}
FOR(i,0,3){
sort(aLL(v[i]));
sm[i].pb(0);
for(pt x:v[i]) sm[i].pb(x.fi+sm[i].back());
}
LL ans=2e18;
int A,B,C,T;
for(int t=max(0,2*k-m);t<=v[0].size()&&t<=m;t++){
int tt=max(0,k-t);
// cout<
if(v[1].size()<tt||v[2].size()<tt) continue;
int l=0,r=1e5,num;
int a=0,b=0,c=0;
while(l<=r){
int mid=l+r>>1;
int aa=max(0,lower_bound(aLL(v[1]),mp(mid,INF))-v[1].begin()-tt);
int bb=max(0,lower_bound(aLL(v[2]),mp(mid,INF))-v[2].begin()-tt);
int cc=lower_bound(aLL(v[3]),mp(mid,INF))-v[3].begin();
// cout<
if(aa+bb+cc>=m-t-2*tt){
num=mid;a=aa;b=bb;c=cc;
r=mid-1;
}
else l=mid+1;
}
// cout<
if(a+b+c+t<m-2*tt) continue;
else if(a+b+c+t==m-2*tt){
LL res=sm[0][t]+sm[1][a+tt]+sm[2][b+tt]+sm[3][c];
if(res<ans){
ans=res;A=a;B=b;C=c;T=t;
}
}
else{
LL res=sm[0][t]+sm[1][a+tt]+sm[2][b+tt]+sm[3][c]-(a+b+c-(m-t-2*tt))*num;
if(res<ans){
ans=res;A=a;B=b;C=c;T=t;
}
}
// cout<
}
if(ans==2e18){
cout<<-1<<endl;
return 0;
}
int len=max(0,k-T);
cout<<ans<<endl;
FOR(i,0,T-1) cout<<v[0][i].se<<' ';
FOR(i,0,len-1) cout<<v[1][i].se<<' ';
FOR(i,0,len-1) cout<<v[2][i].se<<' ';
vector<pt> pp;
FOR(i,1,A) pp.pb(v[1][len+i-1]);
FOR(i,1,B) pp.pb(v[2][len+i-1]);
FOR(i,1,C) pp.pb(v[3][i-1]);
sort(aLL(pp));
FOR(i,1,m-T-2*len) cout<<pp[i-1].se<<' ';
cout<<endl;
return 0;
}
题中所属的交换方式,只能改变偶数个逆序对,假如一个序列只有奇数个逆序对,那肯定不行?
如果这个逆序对中有相同的元素,其实他也可以。
我们可以采用类似于选择排序的思想,每次选择一个最小的,将它放在最前面。假如现在最小的在pos,目标将其放在i。如果他们相差2个位置还多,直接交换(pos-2,pos-1,pos)。否则先交换(pos-1,pos,pos+1),然后位置又相差2了,交换(pos-2,pos-1,pos),就ok了。
int n,m;
char str[N];
pt f[N];
int g[N];
void sswarp(int now)
{
swap(g[now],g[now+2]);
swap(g[now+1],g[now+2]);
}
int main()
{
int t;
r(t);
while(t--){
r(n);
FOR(i,1,n){
int a;
r(a);
f[i]=mp(a,i);
}
sort(f+1,f+n+1);
FOR(i,1,n){
g[f[i].se]=i;
}
int cnt=0;
FOR(i,1,n){
FOR(j,i+1,n){
if(g[i]>g[j]) cnt++;
}
}
bool flag=0;
if(cnt&1){
FOR(i,1,n-1){
if(f[i].fi==f[i+1].fi){
swap(g[f[i].se],g[f[i+1].se]);
flag=1;
break;
}
}
}
if(!flag&&(cnt&1)){
cout<<-1<<endl;
continue;
}
vector<int> ans;
FOR(i,1,n-2){
// FOR(j,1,n) cout<
// cout<
int pos=min_element(g+i,g+n+1)-g;
// cout<<'x'<
while(pos!=i){
if(pos-i>=2){
sswarp(pos-2);
ans.pb(pos-2);
pos-=2;
}
else if(pos-i==1){
sswarp(pos-1);
ans.pb(pos-1);
pos++;
}
}
}
cout<<ans.size()<<endl;
for(int x:ans) cout<<x<<' ';
cout<<endl;
}
return 0;
}