Codeforces Round #532 (Div. 2)

A. Roman and Browser

题意:给出k,让你求b,使所有位置c(c满足c = b + i * k) 的标签全部消失,使1和-1的数量相差最大,求b。

枚举。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,k;
int aa,bb;
int p;
int v[110];
int main(){
    while(cin>>n>>k)
    {
        p=1000*k;
        for(int i=1;i<=n;i++)
        {
            int u;
            cin>>v[i];
            if(v[i]>0)aa++;
            else bb++;
        }
        int ans=0;
        for(int b=1;b<=n;b++)
        {
            int xx=aa,yy=bb;
            for(int j=b-1;j>0;j--)
            {
                if((b-j)%k==0)
                {
                    if(v[j]>0)xx--;
                    else yy--;
                }
            } 
            for(int j=b;j<=n;j++)
            {
                if((j-b)%k==0)
                {
                    if(v[j]>0)xx--;
                    else yy--;
                }
            }
            ans=max(ans,abs(xx-yy));
        }
        cout<<ans<<endl;
    }
}
View Code

 

B. Build a Contest

题意:依次给出数字,当凑足了1-n时输出1,否则输出0。

记录当前位置有几个数字了,凑满数字就所有vis(次数数组减一),一开始居然想到用线段树维护维护这个减一操作和查询次数,因为觉得n太大了每次都扫一遍会超时。后来发现,由于m时固定的,所以扫描n的次数最多是m/n次,每次要n的时间,所以就是o(m)的时间。所以暴力不会出事。

#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,m;
int a[maxn];
int vis[maxn];
string ans;
int main(){
    while(cin>>n>>m)
    {
        CLR(vis,0);
        ans="";
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&a[i]);
        }
        int tot=0;
        for(int i=1;i<=m;i++)
        {
            if(vis[a[i]]==0){
                tot++;
                vis[a[i]]=1;
            }else{
                vis[a[i]]++;
            }
            if(tot<n)ans+="0";
            else{
                ans+="1";
                tot=0;
                for(int j=1;j<=n;j++)
                {
                    vis[j]--;
                    if(vis[j]>0)tot++;
                }
            }
        }
        cout<<ans<<endl;
    }
}
View Code

 

C. NN and the Optical Illusion

初中计算几何题,设外半径为R,半径为r,可以列方程,会解二元一次方程就可以,直接套求根公式。

#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=100010;
const double pai=acos(-1.0);
double n,r,R,p,die;
int main(){
    while(cin>>n>>r)
    {
        p=cos(2*pai/n);
    //    cout<<p<<endl;
        die=(4*r*p-4*r)*(4*r*p-4*r)-4*(2+2*p)*(2*r*r*p-2*r*r);
        double ans=((4*r-4*r*p)+sqrt(die))/(4+4*p);
        printf("%.8f\n",ans);
    }
}
View Code

 

D. Dasha and Chess

交互题,学习了博客,题意好像又搞错了,看了博客后,代码就跟默写一样了……交互题还是不太会啊。

就是要记住,方向数组的变化, i 和 j 对应的是y 和 x,不要弄反了。

转一位大佬的博客,讲的很清晰。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
int fx[4][2]={{1,1},{1,-1},{-1,1},{-1,-1}};
int vis[maxn][maxn],bx[680],by[680],u,px,py,x,y;
int s1[10],s2[10];
void Move(int xx,int yy){
    x+=xx;
    y+=yy;
    if(vis[x][y])x-=xx;
    printf("%d %d\n",x,y);
    fflush(stdout);
    scanf("%d%d%d",&u,&px,&py);
    if(u==-1&&px==-1&&py==-1)exit(0);
    vis[bx[u]][by[u]]=0;
    vis[px][py]=1;
    bx[u]=px;
    by[u]=py;
    
}
int main(){
    cin>>x>>y;
    for(int i=1;i<=666;i++)
    {
        scanf("%d%d",&bx[i],&by[i]);
        vis[bx[i]][by[i]]=1;
    }
    while(x<500)Move(1,0);
    while(y<500)Move(0,1);
    while(x>500)Move(-1,0);
    while(y>500)Move(0,-1);
    for(int i=1;i<=499;i++) for(int j=1;j<=499;j++) if(vis[i][j]) s1[1]++;
    for(int i=1;i<=499;i++) for(int j=501;j<=999;j++) if(vis[i][j]) s1[2]++;
    for(int i=501;i<=999;i++) for(int j=1;j<=499;j++) if(vis[i][j]) s1[3]++;
    for(int i=501;i<=999;i++) for(int j=501;j<=999;j++) if(vis[i][j]) s1[4]++;
    s2[1]=s1[2]+s1[3]+s1[4];
    s2[2]=s1[1]+s1[3]+s1[4];
    s2[3]=s1[1]+s1[2]+s1[4];
    s2[4]=s1[1]+s1[2]+s1[3];
    int maxx=0,tep;
    for(int i=1;i<=4;i++)
    {
        if(s2[i]>maxx){
            maxx=s2[i];
            tep=i-1;
        }
    }
    while(true)
    {
        Move(fx[tep][0],fx[tep][1]);
    }
    
}
View Code

 

 

E. Andrew and Taxi

题意:给出一副有向图,每条边的权值是代表使这条边反向所需要的能力,现在希望使整幅图无环,并且只要使一条边反向了,其他所有权值小于等于这条边的边都可以免费反向。

题解:显然是一个可以二分的题目,因为对所有边进行合法操作必然能得到一个合法的图,这个limit越小则限制越严格。

对于一个二分出来的权值k,我们可以先把所有权值小于等于k的边全部取消,而其他边全部变成拓扑偏序关系,由于取消掉了这些边,所以这些边的影响相当于是最后由我决定的,只要我能写出合法的拓扑序列,那我按照这个拓扑序列来决定边的方向即可。合法的拓扑序列即拓扑完成后元素个数等于n(否则说明有环,元素还在队列里)。

不断二分k,那怎么根据拓扑序列来决定边的方向呢?其实就是看每个元素的拓扑序号是多少,比如u和v,如果u有一条连向v的有向边,但u的拓扑序号却比v的拓扑序号大,说明在拓扑序列中,u在v的后面,所以这条边要被反向,即输出。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n,m;
struct node{
    int u,v;
    ll w;
};
struct edge{
    int to,Next;
}e[maxn];
vector<node >a;
int u,v,tot,head[maxn],d[maxn],top[maxn];
ll w,l,r,mid; 
void addv(int u,int v){
    e[++tot].to=v;
    e[tot].Next=head[u];
    head[u]=tot;
}
bool toposort(){
    queue<int >q;
    int cnt=0; 
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0){
            q.push(i);
        }
    }
    while(!q.empty())
    {
        int u=q.front();
        top[u]=++cnt;
        q.pop();
        for(int i=head[u];i!=-1;i=e[i].Next)
        {
            int v=e[i].to;
            d[v]--;
            if(d[v]==0)
            {
                q.push(v);
            }
        }
    }
    if(cnt==n)return true;
    return false;
}
void buildGraph(ll mid){
    clr(head,-1),tot=0;
    clr(d,0);
    for(int i=0;i<m;i++)
    {
        int st=a[i].u,ed=a[i].v;
        ll val=a[i].w;
        if(val>mid){
            addv(st,ed);
            d[ed]++;
        }
    }
}
vector<int >ans;
int main(){
    while(cin>>n>>m)
    {
        a.clear();
        ans.clear();
        l=0,r=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%lld",&u,&v,&w);
            a.push_back({u,v,w});
            r=max(r,w);
        }
        while(l<r)
        {
            mid=(l+r)>>1;
            buildGraph(mid);
            if(toposort()){
                r=mid;
            }else {
                l=mid+1;
            }
        }
        buildGraph(r);
        toposort();
        for(int i=0;i<m;i++)
        {
            if(a[i].w<=r && top[a[i].u]>top[a[i].v])ans.push_back(i+1);
        }
        int si=ans.size();
        printf("%lld %d\n",r,si);
        for(int i=0;i<si;i++)
        {
            printf("%d%c",ans[i]," \n"[i==si-1]);
        }
        
    }
}
View Code

 

F. Ivan and Burgers

给出 n 个数,q次区间查询,每次查询,让你选择任意个下标为 [ l , r ] 区间内的任意数,使这些数异或起来最大,输出最大值。

思路:离线加线性基。

线性基学习博客1

线性基学习博客2

对于此题,先把区间按照 r 从小到大排序,然后依次处理这些区间,每次插入线性基时,优先保留下标比较大的线性基。查询时,只异或上下标大于 l 的值。

记住异或的符号的优先级很低,所以  if( res^p[i] > res )这样的代码是会wa死的,要注意(这道题这么写,样例都过不了)

 

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=5e5+10;
int a[maxn],q,n,p[30],pos[30],ans[maxn];
struct node{
    int l,r,id;
    friend bool operator<(const node &a,const node &b)
    {
        return a.r<b.r;
    }
}op[maxn]; 
void init(){
    clr(p,0);
}
void add(int val,int id){
    for(int i=20;i>=0;i--)
    {
        if(val&(1<<i))
        {
            if(!p[i]){
                p[i]=val,pos[i]=id;
                break;
            }
            if(pos[i]<id){
                swap(pos[i],id),swap(val,p[i]);
            }
            val^=p[i];
        }
    }
}
int query(int l)
{
    int res=0;
    for(int i=20;i>=0;i--)
    {
        if(pos[i]>=l)
        {
            if((res^p[i])>res)
            {
                res=res^p[i];
            }
        }
    }
    return res;
}
int main(){
    while(cin>>n)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        cin>>q;
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&op[i].l,&op[i].r);
            op[i].id=i;
        }
        sort(op+1,op+1+q);
        int l=1;
        for(int i=1;i<=q;i++)
        {
            while(l<=op[i].r&&l<=n)
            {
                add(a[l],l);
                l++;
            }
            ans[op[i].id]=query(op[i].l);
        }
        for(int i=1;i<=q;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
}
View Code

 

posted @ 2019-02-01 16:28  光芒万丈小太阳  阅读(241)  评论(0编辑  收藏  举报