比赛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 <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;
- }
#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;
- }
#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;
- }
#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;
- }
#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;
- }
#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;
- }
#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;
- }