A-译码
思路:用string a[]数组来保存编码所对于的字符串,对于所给的数字串将其每5个转换为编码即可。
Code A:
#include<iostream>
using namespace std;
const int MAX_N=20005;
const int MAX_M=1005;
int T,n,m;
string a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
int t=0;
for(int i=0;i<26;++i)
for(int j=0;j<26;++j)
for(int k=0;k<26;++k)
{
a[t]=char(i+'a');
a[t]+=char(j+'a');
a[t++]+=char(k+'a');
}
cin>>T;
string str;
while(T--){
cin>>n>>str;
for(int i=0;i<n;)
{
int t=0;
for(int j=0;j<5;++j)
t=t*10+(str[i++]-'0');
cout<<a[t];
}
cout<<endl;
}
return 0;
}
B-Fence Repair
思路:直接暴力。。。
Code B:
#include<iostream>
#include<cstring>
using namespace std;
const int MAX_N=1005;
int n;
int a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
memset(a,0,sizeof(a));
for(int i=0;i<n;++i)
cin>>a[i];
int ans=0;
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
if(a[i]*2==a[j]) ans++;
cout<<ans<<endl;
}
return 0;
}
C-有趣的二进制
思路:这题交了15遍。。。按照其原码到补码的转换过程写,开始是由于没有用 long long 导致错误,改了后又是段错误,交了几遍发现是由于位运算搞的鬼,把 n&1改成n%2,n>>=1改成n/=2就过了。。。
Code C:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL n;
LL a[105];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
memset(a,0,sizeof(a));
int t=0;
LL ans=0;
if(n<0){
ans=1;
n=-n;
}
while(n){
a[t++]=n%2;
n/=2;
}
t=64;
if(ans){
for(int i=0;i<t-1;++i)
if(a[i]) a[i]=0;
else a[i]=1;
int p=1;
for(int i=0;i<t-1;++i)
{
a[i]=a[i]+p;
p=a[i]/2;
a[i]=a[i]%2;
}
}
for(int i=0;i<t-1;++i)
if(a[i]) ans++;
cout<<ans<<endl;
}
return 0;
}
看大佬的代码还可以这样做,佩服佩服
Code C:
#include<iostream>
using namespace std;
unsigned long long n;
int main(){
while(cin>>n){
long long ans=0;
while(n){
if(n&1) ans++;
n>>=1;
}
cout<<ans<<endl;
}
return 0;
}
D-有趣的数字
思路:暴力出前20个找规律即可,还是很好找规律的
Code D:
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
LL n;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
LL s=sqrt(n);
cout<<n-s<<endl;
}
return 0;
}
E-邝博士的问题
思路: 分别计算出 向下和向上取整的金银铜牌的数量a,b,c,aa,bb,cc,则金牌的变换数即为aa-a,银牌为aa+bb-a-b,铜牌为aa+bb+cc-a-b-c;
Code E:
#include<iostream>
using namespace std;
typedef long long LL;
LL n;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
LL a,b,c;
LL aa,bb,cc;
a=n/10; aa=(n+9)/10;
b=n/5; bb=(n+4)/5;
c=n*3/10; cc=(n*3+9)/10;
LL s1,s2,s3;
s1=aa-a; s2=aa+bb-a-b; s3=aa+bb+cc-a-b-c;
cout<<s1<<" "<<s2<<" "<<s3<<endl;
}
return 0;
}
F-新田忌赛马
思路一:贪心+二分,先赢得价值大的马,则将齐威王的马按照其价值按从大到小排序,对于相同价值的按照速度由小到大排序。在将田忌的马按速度由小到大排序,遍历齐威王的马,每次用二分查找到最小比齐威王马速度大的田忌的马,用 boo[i]标记已经比赛过的马,向后找到一个没有标记过马比赛即可
思路二:贪心+优先队列, 将齐威王和田忌的马分别按照其速度按从大到小排序,遍历田忌的马d[i],将所有齐威王的速度比d[i]小的马放入优先队列中,每次取队列中最大价值,这样所有没有加入队列和队列中剩余的都是田忌马要输的,再减去其价值即可。
Code F 1:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
int x;
int w;
bool operator<(const node &p)const{
if(w==p.w){
return x<p.x;
}else return w>p.w;
}
};
const int MAX_N=1005;
int n,T;
node a[MAX_N];
int d[MAX_N];
bool boo[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--){
memset(boo,0,sizeof(boo));
cin>>n;
for(int i=0;i<n;++i)
cin>>a[i].x;
for(int i=0;i<n;++i)
cin>>a[i].w;
for(int i=0;i<n;++i)
cin>>d[i];
sort(a,a+n);
sort(d,d+n);
int ans=0;
for(int i=0;i<n;++i)
{
int k=lower_bound(d,d+n,a[i].x+1)-d;
bool p=false;
for(int j=k;j<n;++j)
if(boo[j]==false){
p=true;
boo[j]=true;
ans+=a[i].w;
break;
}
if(p==false) ans-=a[i].w;
}
cout<<ans<<endl;
}
return 0;
}
Code F 2:
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
struct node{
int x;
int w;
bool operator<(const node &p)const{
return x<p.x;
}
};
const int MAX_N=1005;
int n,T;
node a[MAX_N];
int d[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n;
for(int i=0;i<n;++i)
cin>>a[i].x;
for(int i=0;i<n;++i)
cin>>a[i].w;
for(int i=0;i<n;++i)
cin>>d[i];
sort(a,a+n);
sort(d,d+n);
priority_queue<int> Q;
int ans=0,k=0;
for(int i=0;i<n;++i)
{
while(k<n&&a[k].x<d[i]){
Q.push(a[k++].w);
}
if(!Q.empty()){
ans+=Q.top(); Q.pop();
}
}
while(!Q.empty()){
ans-=Q.top(); Q.pop();
}
while(k<n){
ans-=a[k++].w;
}
cout<<ans<<endl;
}
return 0;
}
G-组合游戏
思路:贪心,先合并长度最小的两块木板,可以用优先队列来维护最小长度。
Code G:
#include<iostream>
#include<queue>
using namespace std;
int n;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
priority_queue<int,vector<int>,greater<int> > Q;
for(int i=0,x;i<n;++i)
{
cin>>x;
Q.push(x);
}
int ans=0,t1,t2;
while(Q.size()>1){
t1=Q.top(); Q.pop();
t2=Q.top(); Q.pop();
ans+=t1+t2;
Q.push(t1+t2);
}
cout<<ans<<endl;
}
return 0;
}
H-渴望力量吗
思路: 力量太弱。。。先挖个坑,以后填上QAQ
恩,这题我一段代码改了无数遍,结果TM是多组数据的问题,我TM。。。 (╯°Д°)╯( ┻━┻再特么的掀一次
恩,我平复下心情。。。
这题是 排序+二分, 由于求 区间[l,r]中为x个个数,因此可以用结构体 node{ int x;int id;} a[] 存元素的值和下标, 对其按照先x由小到大排序,再id由小到大排序,这样 对于每次询问 l,r,x,则只要找到 node{x,l}和 {x,r}在 a[]中的位置下标相减即可。
Code H:
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int x;
int id;
bool operator<(const node &p)const{
if(x==p.x){
return id<p.id;
}else return x<p.x;
}
};
const int MAX_N=300005;
int n,Q;
node a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
for(int i=0;i<n;++i)
{
cin>>a[i].x;
a[i].id=i+1;
}
sort(a,a+n);
cin>>Q;
int l,r,x;
for(int i=0;i<Q;++i)
{
cin>>l>>r>>x;
int L=lower_bound(a,a+n,node{x,l})-a;
int R=upper_bound(a,a+n,node{x,r})-a;
cout<<R-L<<endl;
}
}
return 0;
}
也可以用 pair<int,int>来排序
Code H :
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX_N=300005;
int n,Q;
pair<int,int> data[MAX_N];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
for(int i=0;i<n;i++)
{
cin>>data[i].first;
data[i].second=i+1;
}
sort(data,data+n);
cin>>Q;
int l,r,x;
for(int i=0;i<Q;++i)
{
cin>>l>>r>>x;
pair<int, int>* ll=lower_bound(data,data+n,pair<int,int>(x,l));
pair<int, int>* rr=upper_bound(data,data+n,pair<int,int>(x,r));
cout<<rr-ll<<endl;
}
}
return 0;
}
I-背包问题
思路:DFS+二分 比赛后突然灵光一现才ac掉,对于dp的话时间复杂度为 n*m=10^10肯定超时,而利用搜索,每个物体取和不取,复杂度也有 2^30=10^9也会超时(但是我看ac掉的代码竟然有这种思路过的,还只要2ms。。。这数据TM坑爹啊 (╯°Д°)╯︵ ┻━┻ )
由于直接搜索会超时,因此可以分别把前一半和后一半的所有情况搜索出来保存在数组 d1[],d2[]中,在将d2[]由小到大排序,在遍历d1[],每次只要 找到用二分查找到p=m-d1[i]+1在d2[]中的下标位置k,则ans+=k;这样最终ans就是所有的放法。这样的时间复杂度为 O(2^(n/2)*log(2^(n/2))=10^5
Code I:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAX_N=100005;
int n,S,ans;
int n1,n2;
LL a[MAX_N];
LL d1[MAX_N],d2[MAX_N];
void DFS(int k,int m,LL sum);
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>S){
ans=n1=n2=0;
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
for(int i=0;i<n;++i)
cin>>a[i];
DFS(0,n/2,0);
n1=n2; n2=0;
for(int i=0;i<n1;++i)
d1[i]=d2[i];
DFS(n/2,n,0);
sort(d2,d2+n2);
for(int i=0;i<n1;++i)
{
int p=S-d1[i];
int k=lower_bound(d2,d2+n2,p+1)-d2;
ans+=k;
}
cout<<ans<<endl;
}
return 0;
}
void DFS(int k,int m,LL sum)
{
if(k==m){
if(sum<=S) d2[n2++]=sum;
return;
}
DFS(k+1,m,sum);
DFS(k+1,m,sum+a[k]);
}
J-are you ok 雷总的are you ok 。。。
思路 :线段树+二分查找 利用线段树维护区间的最大值,再用二分查找每次的询问值x,并修改其前一位值即可
Code J:
#include<iostream>
#include<stdio.h>
using namespace std;
const int MAX_N=1000006;
int n,Q;
int a[MAX_N];
int tree[MAX_N<<2];
void PushUp(int t);
void Build(int l,int r,int t);
void Update(int id,int x,int L,int R,int t);
int Query(int l,int r,int L,int R,int t);
int Lower_bound(int l,int r,int x);
int main()
{
// ios::sync_with_stdio(false);
while(~scanf("%d%d",&n,&Q)){
// memset(tree,0,sizeof(tree));
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
//cin>>a[i];
Build(1,n,1);
for(int i=0,x;i<Q;++i)
{
scanf("%d",&x);
// cin>>x;
int k=Lower_bound(1,n,x);
// cout<<"## ";
if(k!=n){
printf("%d\n",k);
//cout<<k<<endl;
if(k>=1){
a[k]++;
Update(k,a[k],1,n,1);
}
}else// cout<<"are you ok"<<endl;
printf("are you ok\n");
}
}
return 0;
}
void PushUp(int t)
{
tree[t]=max(tree[t<<1],tree[t<<1|1]);
}
void Build(int l,int r,int t)
{
if(l==r){
tree[t]=a[r];
return;
}
int h=(l+r)>>1;
Build(l,h,t<<1);
Build(h+1,r,t<<1|1);
PushUp(t);
}
void Update(int id,int x,int l,int r,int t)
{
if(l==r){
tree[t]=x;
return;
}
int h=(l+r)>>1;
if(h>=id){
Update(id,x,l,h,t<<1);
}else Update(id,x,h+1,r,t<<1|1);
PushUp(t);
}
int Query(int l,int r,int L,int R,int t)
{
if(L>=l&&R<=r){
return tree[t];
}
int h=(L+R)>>1,s1=0,s2=0;
if(h>=l) s1=Query(l,r,L,h,t<<1);
if(h+1<=r) s2=Query(l,r,h+1,R,t<<1|1);
return max(s1,s2);
}
int Lower_bound(int l,int r,int x)
{
while(l<=r){
int h=(l+r)>>1;
if(Query(1,h,1,n,1)>=x) r=h-1;
else l=h+1;
}
return l-1;
}
K-序列求和
思路 :对于前 n2和 S=n*(n+1)*(2*n+1)/6,而 S要对 MOD=1000000007取模;由于S中要除以6,因此可以用乘法逆元求出6对于MOD的逆元 P=166666668; 那么 ans=(S%MOD*(P%MOD))%MOD即可,另一种思路是 用n*(n+1)*(2*n+1)提前消除6,n或(n+1)可以消除2,而n (n+1) (2*n+1)三种间必然有一个可以消除3,这样就可以直接取模了。
Code K:
#include<iostream>
using namespace std;
typedef long long LL;
const LL MOD=1000000007;
const LL P=166666668; //6对于MOD的逆元
LL n;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n){
LL a=n,b=n+1,c=2*n+1;
// LL ans=(((a%MOD*(b%MOD))%MOD*(c%MOD))%MOD*(P%MOD))%MOD; //利用乘法逆元
if(a%2==0) a/=2;
else b/=2;
if(a%3==0) a/=3;
else if(b%3==0) b/=3;
else c/=3;
LL ans=((a%MOD*(b%MOD))%MOD*(c%MOD))%MOD;
cout<<ans<<endl;
}
return 0;
}