比赛t题目链接:
https://www.nowcoder.com/acm/contest/77#question
A .逆序数
思路:直接用分治法求逆序数即可,这里也可以用树状数组求,数据也不大。所以不用离散求处理下输入0即可。
附上两个不同版本的代码:
分治:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int num[100005],c[100005];
ll ans ;
void margeHe(int S,int mid,int E){
int s=S,m = mid+1,cnt = s;
while(s<=mid&&m<=E){
if(num[s]<=num[m]){
c[cnt++] = num[s++];
}
else{
c[cnt++] = num[m++];
ans+=mid-s+1;
}
}
while(s<=mid){
c[cnt++] = num[s++];
}
while(m<=E){
c[cnt++] = num[m++];
}
for(int i=S;i<=E;i++){
num[i] = c[i]; //合并过程排好序
}
}
void marge(int S,int E){
if(S>=E) return ;
int mid = (S+E)>>1;
marge(S,mid);
marge(mid+1,E);
margeHe(S,mid,E);
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>num[i];
ans = 0;
marge(1,n);
cout<<ans<<endl;
return 0;
}
树状数组:
#include <iostream>
#include <cstring>
using namespace std;
#define N 500005
typedef long long ll;
int c[N];
int n;
ll lowbit(ll i)
{
return i&(-i);
}
ll insert(ll i,ll x)
{
while(i<=n&&i!=0){
c[i]+=x;
i+=lowbit(i);
}
return 0;
}
ll getsum(ll i)
{
ll sum=0;
while(i>0){
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
while(cin>>n){
ll ans=0;
memset(c,0,sizeof(c));
ll cnt = 0;
for(int i=1;i<=n;i++){
int a;
cin>>a;
insert(a,1);
if(a==0){
++cnt; //注意处理0输入即可
ans +=i-cnt;
}
else
ans+=i-(getsum(a)+cnt);//统计当前序列中大于a的元素的个数
}
cout<<ans<<endl;
}
return 0;
}
B.Big Water Problem
思路:裸的树状数组,裸的单点修改和区间查询(QAQ!!据说可以暴力????
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+11;
typedef long long ll;
int sum ;
int n,m;
ll tree[maxn];
int lowbit(int t)
{
return t&(-t);
}
void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=y;
}
ll getsum(int x)
{
ll ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=tree[i];
return ans;
}
ll getqujiansum(int x1,int x2){
return getsum(x2)-getsum(x1-1);
}
int main(){
int a;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a;
add(i,a);
}
int x,y;
for(int i=0;i<m;i++){
cin>>a;
if(a==1){
cin>>x>>y;
add(x,y);
}
if(a==2){
cin>>x>>y;
cout<<getqujiansum(x,y)<<endl;
}
}
return 0;
}
C.字符串问题
思路:先预处理next数组,得到输入字符串的前后缀关系,并开另一数组记录关系,从next数组最后即串
的长度+1开始往回回溯看是否满足条件即可.(一拿题想多了。。。其实可能存在多个字串满足,我们根据
next数组就能找到其中一个即可。)。还是不明白的,输出next数组找找思路.
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 1000010;
char s[maxn];
int nxt[maxn];
int mark[maxn];
void get_next(int len)
{
int i = 0, j = -1;
nxt[0] = -1;
while (i < len)
{
if (j == -1 || s[i] == s[j])
nxt[++i] = ++j;
else j = nxt[j];
}
}
int main()
{
cin>>s;
int len = strlen(s);
memset(mark,0,sizeof(mark));
get_next(len);
for(int i=0;i<len;i++){
mark[nxt[i]]++;
}
int i = nxt[len];
bool flag = 1;
while (i)
{
if (mark[i]) {
for (int j = 0; j < i; j++)
cout<<s[j];
cout<<endl;
flag = 0;
break;
}
i = nxt[i];
}
if(flag)
cout<<"Just a legend"<<endl;
}
D.集合问题
小编太弱了,没做道这题,看了题解,菊苣用并查集...不过从后面读了下题,感觉能够用开两个vector+二分能做???过后补题试试..
E.情人节的电灯泡
思路:二维树状数组的单点修改,区间查询,直接上代码 (暴力居然能过,再也不相信数据水到这程度...)
#include <bits/stdc++.h>
using namespace std;
int n,q;
int num[1005][1005],tree[1005][1005];
int lowbit(int t){
return t&(-t);
}
void add(int x,int y,int val){
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=n;j+=lowbit(j)){
tree[i][j] +=val;
}
}
}
int getsum(int x,int y){
int sum = 0;
for(int i=x;i>0;i-=lowbit(i)){
for(int j=y;j>0;j-=lowbit(j)){
sum+=tree[i][j];
}
}
return sum;
}
int main(){
int a,x,y,x1,x2,y1,y2;
cin>>n>>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>num[i][j];
if(num[i][j]){
add(i,j,1);
}
}
}
for(int i=1;i<=q;i++){
cin>>a;
if(a==1){
cin>>x>>y;
if(num[x][y]){
add(x,y,-1);
}else{
add(x,y,1);
}
num[x][y]^=1;
}
if(a==2){
cin>>x1>>y1>>x2>>y2;
cout<<getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1)<<endl;
}
}
return 0;
}
F .The Biggest Water Problem
签到题
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+11;
int sum ;
int ji(int su){
sum = 0;
while(su){
int t = su%10;
su /=10;
sum+=t;
}
if(sum<10) return sum;
else ji(sum);
return sum;
}
int main(){
int su;
cin>>su;
cout<<ji(su)<<endl;
return 0;
}
G 送分啦-QAQ
思路:斐波那序博弈(不会博弈的,要好好了解博弈...
#include <iostream>
#include <stdio.h>
using namespace std;
typedef long long ll;
ll fib[1000];
ll ans;
void init(){
fib[0] = 1;
fib[1] = 1;
for(int i=2;i<=1000;i++){
fib[i] = fib[i-1]+fib[i-2];
}
}
int main()
{
int n;
init();
cin>>n;
int i;
for(i=0;i<45;i++){
if(fib[i]==n) break;
}
if(i<45){
cout<<"Sha"<<endl;
}
else
cout<<"Xian"<<endl;
return 0;
}
H Tree Recovery
思路: 裸的线段树 (据说 暴力优化下也能过,哎 感觉最后一场暴力场?吐槽小数据。。。
#include <bits/stdc++.h>
using namespace std;
int n,q;
#define maxn 100007
int Sum[maxn<<2],Add[maxn<<2];
int A[maxn];
void PushUp(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
void PushDown(int rt,int ln,int rn){ //下推标记
if(Add[rt]){
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
Sum[rt<<1]+=Add[rt]*ln;
Sum[rt<<1|1]+=Add[rt]*rn;
Add[rt]=0;
}
}
void Build(int l,int r,int rt){
if(l==r) {
Sum[rt]=A[l];
return;
}
int m=(l+r)>>1;
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
PushUp(rt);
}
void Update(int L,int R,int C,int l,int r,int rt){
if(L <= l && r <= R){
Sum[rt]+=C*(r-l+1);
Add[rt]+=C;
return ;
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);
if(L <= m) Update(L,R,C,l,m,rt<<1);
if(R > m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);
}
int Query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
return Sum[rt];
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);
int ANS=0;
if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>A[i];
}
Build(1,n,1);
int x,y,ad;
char a;
for(int i=1;i<=q;i++){
cin>>a;
if(a=='Q'){
cin>>x>>y;
cout<<Query(x,y,1,n,1)<<endl;
}
if(a=='C'){
cin>>x>>y>>ad;
Update(x,y,ad,1,n,1);
}
}
return 0;
}