zoukankan      html  css  js  c++  java
  • 【Codeforces #168 Div1 & Div2】Solutions

      转载请注明出处:http://www.cnblogs.com/Delostik/archive/2013/02/21/2920087.html

      上一次失误掉进Div2,这次也很可惜,B题读错了题又差一点。。。

    【A.Lights Out】

      http://www.codeforces.com/contest/275/problem/A

      题目大意:按开关会导致周围相邻开关状态一起变化,给出操作问结果。

      简单模拟

    View Code
     1 #include <iostream>
     2 using namespace std;
     3 
     4 const int dx[5]={0,1,0,-1,0};
     5 const int dy[5]={1,0,-1,0,0};
     6 int res[5][5],x;
     7 
     8 int main(){
     9     for(int i=1;i<=3;i++)
    10         for(int j=1;j<=3;j++){
    11             cin>>x;
    12             for(int k=0;k<5;k++)
    13                 res[i+dx[k]][j+dy[k]]+=x;
    14         }
    15     for(int i=1;i<=3;i++){
    16         for(int j=1;j<=3;j++)
    17             cout<<(res[i][j]+1)%2;
    18         cout<<endl;
    19     }
    20     return 0;
    21 }

    【B.Convex Shape】

      http://www.codeforces.com/contest/275/problem/B

      题目大意:判断所给图形是不是所谓"Convex Shape"(即任意两个格子互达且只需转向一次)

      枚举两个格子,沿着路径走就可以了= =竟然读错题了啊囧

    View Code
     1 #include <iostream>
     2 using namespace std;
     3 
     4 int n,m,x[3000],y[3000],cnt;
     5 char s[50][50];
     6 
     7 bool check(int x,int a1,int b1,int y,int a2,int b2){
     8     for(int i=min(a1,b1);i<=max(a1,b1);i++)
     9         if(s[x][i]!='B') return 0;
    10     for(int i=min(a2,b2);i<=max(a2,b2);i++)
    11         if(s[i][y]!='B') return 0;
    12     return 1;
    13 }
    14 
    15 int main(){
    16     cin>>n>>m;
    17     for(int i=0;i<n;i++){
    18         cin>>s[i];
    19         for(int j=0;j<m;j++)
    20             if(s[i][j]=='B') x[++cnt]=i,y[cnt]=j;
    21     }
    22     for(int i=1;i<cnt;i++)
    23         for(int j=i+1;j<=cnt;j++){
    24             if(check(x[i],y[i],y[j],y[j],x[i],x[j])) continue;
    25             if(check(x[j],y[i],y[j],y[i],x[i],x[j])) continue;
    26             cout<<"NO";
    27             return 0;
    28         }
    29     cout<<"YES";
    30     return 0;
    31 }

    【C.k-Multiple Free Set】(A in Div1)

      http://www.codeforces.com/contest/275/problem/C

      http://www.codeforces.com/contest/274/problem/A

      题目大意:从所给数集中找出最大子集,使得子集中不存在x,y,使得y=x*k。求最大子集的大小。

      我思路大体是这样的。。。

      首先我把题目抽象成一个图的问题,对于集合中x,x*k,将他们连边,最后图中会形成若干条链,不同的链一定互不干扰,问题转换成在每条链中选取尽量多的点。

      到这里就可以做了(博主就是这样做的结果时间内存都巨大),但是可以继续想

      选取尽量多的点的一种方法就是:链头上的点先选,然后隔一个点选一个。这样就有了一种贪心的方法,先将集合中数字排序,然后如果该数可选,就选,不可选就不选。

      代码1:贪心方法

    View Code
     1 #include <iostream>
     2 #include <algorithm>
     3 #include <map>
     4 using namespace std;
     5 
     6 map<long long,bool> m;
     7 int n,ans;
     8 long long k,a[100010];
     9 
    10 int main(){
    11     cin>>n>>k;
    12     for(int i=0;i<n;i++)
    13         cin>>a[i];
    14     sort(a,a+n);
    15     for(int i=0;i<n;i++)
    16         if(!m[a[i]]) m[a[i]]=m[a[i]*k]=true;
    17     ans=(k==1)?m.size():m.size()/2;
    18     cout<<ans;
    19     return 0;
    20 }

      代码2:图方法

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <map>
     5 #define mn 100010
     6 #define mm 200020
     7 using namespace std;
     8 typedef long long ll;
     9 
    10 map<long long,int> m;
    11 int cnt[100010],n,ans,tot;
    12 long long k,a[100010];
    13 bool vis[100010];
    14 
    15 struct EDGE{
    16     int pnt;
    17     EDGE *pre;
    18     EDGE(){}
    19     EDGE(int _pnt,EDGE *_pre):pnt(_pnt),pre(_pre){}
    20 }Edge[mm],*SP=Edge,*edge[mn];
    21 
    22 inline void addedge(int a,int b){
    23     edge[a]=new(++SP)EDGE(b,edge[a]);
    24     edge[b]=new(++SP)EDGE(a,edge[b]);
    25 }
    26 
    27 int dfs(int x){
    28     vis[x]=true;
    29     for(EDGE *j=edge[x];j;j=j->pre)
    30         if(!vis[j->pnt]){
    31             cnt[x]+=dfs(j->pnt)    ;
    32         }
    33     return cnt[x];
    34 }    
    35 
    36 int main(){
    37     cin>>n>>k;
    38     for(int i=1;i<=n;i++){
    39         scanf("%d",&a[i]);
    40         cnt[i]=1;
    41     }
    42     sort(a+1,a+1+n);
    43     for(int i=1;i<=n;i++)
    44         if(!m[a[i]]) m[a[i]]=++tot;
    45     n=tot;
    46     for(int i=1;i<=n;i++){
    47         int tmp=m[a[i]*k];
    48         if(tmp>0) addedge(m[a[i]],tmp);
    49     }
    50     for(int i=1;i<=n;i++)
    51         if(!vis[i]){
    52             dfs(i);
    53             ans+=(cnt[i]+1)/2;
    54         }
    55     cout<<ans<<endl;
    56     return 0;
    57 }

    【D.Zero Tree】(B in Div1)

      http://www.codeforces.com/contest/275/problem/D

      http://www.codeforces.com/contest/274/problem/B

      题目大意,给定一棵带权树,每次可以选取包括节点1的一棵子树,使其所有点权±1,问最少操作次数使得所有节点点权为0.

      显然应该先把叶子节点变成0,然后依次向上做。dfs即可

    View Code
     1 #include <iostream>
     2 #define mn 100010
     3 #define mm 200010
     4 using namespace std;
     5 typedef long long ll;
     6 template<class T>inline void gmax(T &a,T b){if(a<b)a=b;}
     7 
     8 struct EDGE{
     9     int pnt;
    10     EDGE *pre;
    11     EDGE(){}
    12     EDGE(int _pnt,EDGE *_pre):pnt(_pnt),pre(_pre){}
    13 }Edge[mm],*SP=Edge,*edge[mn];
    14 
    15 ll add[mn],sub[mn],w[mn];
    16 int n,a,b;
    17 
    18 inline void addedge(int a,int b){
    19     edge[a]=new(++SP)EDGE(b,edge[a]);
    20     edge[b]=new(++SP)EDGE(a,edge[b]);
    21 }
    22 
    23 void dfs(int x,int fa){
    24     ll t_add=0,t_sub=0;
    25     for(EDGE *j=edge[x];j;j=j->pre)
    26         if(j->pnt!=fa){
    27             dfs(j->pnt,x);
    28             gmax(t_add,add[j->pnt]);
    29             gmax(t_sub,sub[j->pnt]);
    30         }
    31     w[x]+=t_add-t_sub;
    32     if(w[x]<0) t_add-=w[x];
    33     else t_sub+=w[x];
    34     add[x]=t_add,sub[x]=t_sub;
    35 }
    36 
    37 int main(){
    38     cin>>n;
    39     for(int i=1;i<n;i++){
    40         cin>>a>>b;
    41         addedge(a,b);
    42     }
    43     for(int i=1;i<=n;i++)
    44         cin>>w[i];
    45     dfs(1,0);
    46     cout<<sub[1]+add[1]<<endl;
    47     return 0;
    48 }

    【E.】The Last Hole!(C in Div 1)

      http://www.codeforces.com/contest/275/problem/E

      http://www.codeforces.com/contest/274/problem/C

      题如其名,最后一题是个坑。。。等会写

    【D.Lovely Matrix】(Div 1)

      http://www.codeforces.com/contest/274/problem/D

      题目大意:n×m格子,格子有权值,有空格,问是否可以交换某些列的次序,使得每一行上的数字不减。

      显然是拓扑排序。问题在于数据范围有点大,如果出现权值相同的格子,建图时逐个连边复杂度非常高。我们可以考虑附加点P[x],使权值为x的点都连向P[x],然后由P[x]连向比x大的点。

    View Code
     1 #include <iostream>
     2 #include <algorithm>
     3 #include <queue>
     4 #define mm 200010
     5 #define mn 400010
     6 using namespace std;
     7 
     8 queue<int> q;
     9 int n,m,ans[mn],deg[mn],cnt,idx;
    10 struct REC{int v,p;}a[mn];
    11 
    12 struct EDGE{
    13     int pnt;
    14     EDGE *pre;
    15     EDGE(){}
    16     EDGE(int _pnt,EDGE *_pre):pnt(_pnt),pre(_pre){}
    17 }Edge[mm],*SP=Edge,*edge[mn];
    18 
    19 inline void addedge(int a,int b){
    20     edge[a]=new(++SP)EDGE(b,edge[a]);
    21     deg[b]++;
    22 }
    23 
    24 inline bool cmp(REC a,REC b){return a.v<b.v;}
    25 
    26 int main(){
    27     cin>>n>>m;
    28     for(int i=0;i<n;i++){
    29         for(int j=0;j<m;j++){
    30             cin>>a[j].v;
    31             a[j].p=j;
    32         }
    33         sort(a,a+m,cmp);
    34         for(int j=0;j<m;j++)
    35             if(a[j].v!=-1){
    36                 if(!j || a[j].v!=a[j-1].v) cnt++;
    37                 addedge(a[j].p,m+cnt+1);
    38                 addedge(m+cnt,a[j].p);
    39             }
    40         cnt++;
    41     }
    42     for(int i=0;i<m+cnt;i++)
    43         if(!deg[i]) q.push(i);
    44     while(!q.empty()){
    45         int i=q.front();q.pop();
    46         if(i<m) ans[++idx]=i;
    47         for(EDGE *j=edge[i];j;j=j->pre)
    48             if(!--deg[j->pnt]) q.push(j->pnt);
    49     }
    50     if(idx<m) cout<<-1;
    51     else for(int i=1;i<=m;i++) 
    52         cout<<ans[i]+1<<" ";
    53     return 0;
    54 }


    【E. Mirror Room】(Div 1)

      http://www.codeforces.com/contest/274/problem/E

      题目大意:光线在镜子格里反射,问能经过多少格子。

      看了liouzhou101大神的代码明白了,其实就是用了一堆map和set然后模拟。。。。

      好不容易仿照着写出来了,但是今天CF评测机抽风,在第24个点tle,连liouzhou101的代码现在都过不了。。。

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <map>
     5 #include <set>
     6 #define x first
     7 #define y second
     8 using namespace std;
     9 typedef pair<int,int> PII;
    10 
    11 int n,m,k,ans,x,y;
    12 set<PII> block,empty_cell;
    13 map<PII,set<PII> > vis;
    14 PII s,t,dir;
    15 char sym[5];
    16 
    17 int main(){
    18     cin>>n>>m>>k;
    19     for(int i=0;i<=n+1;i++)
    20         block.insert(PII(i,0)),
    21         block.insert(PII(i,m+1));
    22     for(int i=0;i<=m+1;i++)
    23         block.insert(PII(0,i)),
    24         block.insert(PII(n+1,i));
    25     while(k--){
    26         scanf("%d%d",&x,&y);
    27         block.insert(PII(x,y));
    28     }
    29     scanf("%d%d",&s.x,&s.y);
    30     scanf("%s",sym);
    31     dir=PII(sym[0]=='N'?-1:1,sym[1]=='W'?-1:1);
    32     while(true){
    33         if(empty_cell.insert(s).y) ans++;
    34         t=PII(s.x+dir.x,s.y+dir.y);
    35         if(!block.count(t)){
    36             s=t;
    37             continue;
    38         }
    39         if(!vis[t].insert(dir).y) break;
    40         x=block.count(PII(t.x-dir.x,t.y)),y=block.count(PII(t.x,t.y-dir.y));
    41         if (x==y) dir.x=-dir.x,dir.y=-dir.y;
    42         else if(x) s.x+=dir.x,dir.y=-dir.y;
    43         else s.y+=dir.y,dir.x=-dir.x;
    44     }
    45     cout<<ans<<endl;
    46     return 0;
    47 }

      

  • 相关阅读:
    目录
    DRF的分页
    Django Rest Framework 视图和路由
    爬虫基本原理
    C# System.Threading.Timer的使用
    C# Task的使用
    C# 线程池的使用
    C# 异步委托回调函数使用
    C#异步委托等待句柄的使用
    C# 异步委托的使用
  • 原文地址:https://www.cnblogs.com/Delostik/p/2920087.html
Copyright © 2011-2022 走看看