怎么说呢,刚开始做的缘故吧,感觉阻力挺大的。但是尽力都搞懂吧。
昨天刚来的时候做了一道题,当时看了不少题也想了不少,但是发现真正能实施的不多,第一个出来的也是我认为比较没有阻力的题目是:
1001 Assignment,这道题听世冬说是个数据结构的贪心解法,但是我以前见过类似的尺取法的题目,所以思路直接就跑向了尺取法,本来信心慢慢,可是发现维护最大最小值并不是简单的区间移动怎么简单,于是加入了线段树优化,最简单的题目过的也不是很顺当。但是思路完全是自己的,并不知道题解怎么写的。
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 100010
using namespace std;
long long a[maxn];
struct xtree{
long long l,r,maxx,minn;
}tree[4*maxn];
void build(long long id,long long l,long long r){
tree[id].l=l,tree[id].r=r;
if(l==r){
tree[id].maxx=a[l],tree[id].minn=a[l];
}
else{
long long mid=(l+r)>>1;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
tree[id].maxx=max(tree[id*2].maxx,tree[id*2+1].maxx);
tree[id].minn=min(tree[id*2].minn,tree[id*2+1].minn);
}
}
long long maxquery(long long id,long long l,long long r){
if(tree[id].l==l&&tree[id].r==r) return tree[id].maxx;
else{
long long mid=(tree[id].l+tree[id].r)>>1;
if(r<=mid) return maxquery(id*2,l,r);
else if (l>mid)return maxquery(id*2+1,l,r);
else{
return max(maxquery(id*2,l,mid),maxquery(id*2+1,mid+1,r));
}
}
}
long long minquery(long long id,long long l,long long r){
if(tree[id].l==l&&tree[id].r==r) return tree[id].minn;
else{
long long mid=(tree[id].l+tree[id].r)>>1;
if(r<=mid) return minquery(id*2,l,r);
else if (l>mid)return minquery(id*2+1,l,r);
else{
return min(minquery(id*2,l,mid),minquery(id*2+1,mid+1,r));
}
}
}
int main(){
long long t;
long long i,j,k,l,n,r;
long long maxx,minn,tot,ans,temp;
scanf("%lld",&t);
while (t--){
scanf("%lld%lld",&n,&k);
for (i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
maxx=minn=a[1];
tot=1,ans=0;
if (n==1){
puts("1");
continue;
}
l=1;
for (i=2;i<=n;i++){
if (a[i]>maxx)maxx=a[i];
if (a[i]<minn)minn=a[i];
if (maxx-minn>=k){
ans+=tot*(tot+1)/2;
for (j=l;j<=i;j++){
if (a[j]<maxx&&a[j]>minn){
tot--;
l++;
continue;
}
else {
l++;
tot--;
maxx=maxquery(1,l,i);
minn=minquery(1,l,i);
if (maxx-minn<k){
break;
}
}
}
ans-=tot*(tot+1)/2;
}
tot++;
if (i==n){
ans+=tot*(tot+1)/2;
}
}
printf("%lld\n",ans);
}
}
然后是一个线段树的题目1018 Gorgeous Sequence(中间看了一道疑似二分法+瞎搞的题目一直tle,是1009Y sequence,我认为的复杂度<64*64*30000,自认为不会超时,看了一眼题解的题头是个容斥定理,但感觉并非, 不知道容斥什么)这道题比较麻烦,是对lazy标记的理解,队友给我说的他看的大致的题解思路,和我的相似于是试了一下,最后还是借助了题解,处理不好总tle。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define maxn 4000010
const long long inf=1000000000;
using namespace std;
long long maxx,sum;
struct xtree{
long long l,r;
long long mid(){
return (l+r)/2;
}
long long lazy;
long long flag;
long long sum,maxx;
}tree[maxn];
long long a[1000010];
void pushup(long long id){
tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
tree[id].maxx=max(tree[id*2].maxx,tree[id*2+1].maxx);
tree[id].flag=tree[id*2].flag+tree[id*2+1].flag;
}
void build(long long id,long long l,long long r){
tree[id].l=l;
tree[id].r=r;
tree[id].lazy=0;
if (l==r){
tree[id].flag=1;
tree[id].lazy=tree[id].sum=tree[id].maxx=a[l];
return ;
}
long long mid=tree[id].mid();
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id);
}
void renew(long long id,long long num){
if (tree[id].lazy<=num&&tree[id].lazy)return ;
tree[id].lazy=num;
tree[id].sum=tree[id].sum+(tree[id].r-tree[id].l+1-tree[id].flag)*num;
if (tree[id].flag<tree[id].r-tree[id].l+1){
tree[id].maxx=num;
tree[id].flag=tree[id].r-tree[id].l+1;
}
}
void pushdown(long long id){
if (!tree[id].lazy)return ;
long long mid=tree[id].mid();
renew(id*2,tree[id].lazy);
renew(id*2+1,tree[id].lazy);
tree[id].lazy=0;
}
void find(long long id,long long num){
if (tree[id].maxx<=num)return;
if (tree[id].lazy>num)tree[id].lazy=0;
if (tree[id].l==tree[id].r){
tree[id].maxx=tree[id].lazy;
tree[id].sum=tree[id].lazy;
tree[id].flag=tree[id].lazy?1:0;
return;
}
pushdown(id);
long long mid=tree[id].mid();
find(id*2,num);
find(id*2+1,num);
pushup(id);
}
void update(long long id,long long l,long long r,long long num){
if (tree[id].maxx<=num)return ;
if (tree[id].l>=l&&r>=tree[id].r){
find(id,num);
renew(id,num);
return;
}
pushdown(id);
long long mid=tree[id].mid();
if(l<=mid) update(id*2,l,r,num);
if(r>mid) update(id*2+1,l,r,num);
pushup(id);
}
void query(long long id,long long l,long long r){
if (l<=tree[id].l&&r>=tree[id].r){
sum+=tree[id].sum;
maxx=max(maxx,tree[id].maxx);
return;
}
pushdown(id);
long long mid=tree[id].mid();
if(l<=mid) query(id*2,l,r);
if(r>mid) query(id*2+1,l,r);
}
int main(){
long long t,n,q,i,j,c,x,y,z;
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&q);
for (i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
while(q--){
scanf("%lld",&c);
if (!c){
scanf("%lld%lld%lld",&x,&y,&z);
update(1,x,y,z);
}
else if(c==1){
sum=0;
maxx=-inf;
scanf("%lld%lld",&x,&y);
query(1,x,y);
printf("%d\n",maxx);
}
else{
sum=0;
maxx=-inf;
scanf("%lld%lld",&x,&y);
query(1,x,y);
printf("%lld\n",sum);
}
}
}
}
然后一个小的暴力题目:1017 Friends,题意求分组方法,但是人数很少,明显暴力,因为有个大的剪枝方案,一开始图省事少用一个数组wr了一发,后来加上秒过。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long vis1[9];
long long vis2[9];
long long d[9];
long long n,m,ans;
struct edge{
long long x;
long long y;
}p[29];
void dfs(long long id){
if (id==m+1){
long long i;
bool flag=1;
for (i=1;i<=n;i++){
if (vis1[i]!=vis2[i]){
flag=0;
break;
}
}
if (flag)ans++;
return;
}
if (vis1[p[id].x]<d[p[id].x]/2&&vis1[p[id].y]<d[p[id].y]/2){
vis1[p[id].x]++;
vis1[p[id].y]++;
dfs(id+1);
vis1[p[id].x]--;
vis1[p[id].y]--;
}
if (vis2[p[id].x]<d[p[id].x]/2&&vis2[p[id].y]<d[p[id].y]/2){
vis2[p[id].x]++;
vis2[p[id].y]++;
dfs(id+1);
vis2[p[id].x]--;
vis2[p[id].y]--;
}
}
int main(){
long long t;
long long i,j;
scanf("%lld",&t);
while (t--){
scanf("%lld%lld",&n,&m);
memset (d,0,sizeof(d));
for (i=1;i<=m;i++){
scanf("%lld%lld",&p[i].x,&p[i].y);
d[p[i].x]++;
d[p[i].y]++;
}
ans=0;
bool flag=1;
for (i=1;i<=n;i++){
if (d[i]%2!=0){
flag=0;
break;
}
}
if (flag){
dfs(1);
printf("%lld\n",ans);
}
else {
puts("0");
}
}
}
之后是都过了的谜之第一题,据说都参考了题解,于是我问队友是不是前面扫一遍后边扫一遍(我一开始的想法)这逗逼说不是,下午又给我说是,还赖帐不认了,但是知道是对的就很自信的写过了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#define maxn 100010
using namespace std;
vector<long long>p[10010];
void getp(){
long long i,j;
for (i=1;i<=10000;i++){
for (j=1;j<=sqrt(i);j++){
if (i%j==0){
p[i].push_back(j);
if (i/j!=j){
p[i].push_back(i/j);
}
}
}
}
}
long long a[maxn];
long long vis[maxn];
long long pre[maxn];
long long to[maxn];
int main(){
getp();
long long n,i,j,k,l;
while (scanf("%lld",&n)!=EOF){
for (i=1;i<=n;i++){
scanf("%lld",&a[i]);
pre[i]=0;
to[i]=n+1;
}
memset (vis,-1,sizeof(vis));
vis[a[1]]=1;
for (i=2;i<=n;i++){
for (j=0;j<p[a[i]].size();j++){
if (vis[p[a[i]][j]]!=-1&&vis[p[a[i]][j]]>pre[i]){
pre[i]=vis[p[a[i]][j]];
}
}
vis[a[i]]=i;
}
memset (vis,-1,sizeof(vis));
vis[a[n]]=n;
for (i=n-1;i>=1;i--){
for (j=0;j<p[a[i]].size();j++){
if (vis[p[a[i]][j]]!=-1&&vis[p[a[i]][j]]<to[i]){
to[i]=vis[p[a[i]][j]];
}
}
vis[a[i]]=i;
}
long long ans=0;
for (i=1;i<=n;i++){
//cout<<i<<' '<<pre[i]<<' '<<to[i]<<endl;
ans=(ans+(to[i]-i)*(i-pre[i]))%1000000007;
}
printf("%lld\n",ans);
}
}