2015 ICPC 沈阳网赛 解题报告

        这把打得真是水,简直不能忍,题数就差了2题,木有出线,我要背锅。。


1012 Largest Point

        这题我并没有码,讲讲思路就好了。要求一个式子最大值,分析一下发现可以贪心搞,把最大2个数、最小2个数、绝对值最小2个数找出来,注意不用sort,然后暴力试这6个数就好了。学弟很给力1A了。


1006 Fang Fang

        如果字符串中全是f,那么就是(len+1)/2。如果是c和f,随便把一个c循环到开头,检查两个c之间和最后一个c到末尾的f是否达到2个以上。然而我写了bug坑了几发。

#include <iostream>     
#include <cstdio>     
#include <algorithm>     
#include <set>    
#include <vector>    
#include <string.h>    
#include <queue>  
#include <map>  
using namespace std;

#define ll long long


char str[1000010];
char str2[1000010];

int main(){
    int t;
    cin>>t;
    int cas=0;
    
    while(t--){
        cas++;
        scanf("%s",str);
        int len=strlen(str);
        int firstC=-1;
        for(int i=0;i<len;i++){
            if(str[i]=='c'){
                firstC=i;
                break;
            }
        }
        
        printf("Case #%d: ",cas);
        bool woca=0;
        for(int i=0;i<len;i++){
            if(str[i]!='c'&&str[i]!='f'){
                woca=1;break;
            }
        }
        if(woca){
            printf("-1\n");
            continue;
        }
        if(firstC==-1){
            printf("%d\n",(len+1)>>1);
        }else{
            for(int i=firstC;i<len;i++){
                str2[i-firstC]=str[i];
            }
            for(int i=0;i<firstC;i++){
                str2[i+len-firstC]=str[i];
            }
            bool ok=1;
            int cnt=0;
            int ans=0;

            for(int i=1;i<=len;i++){
                if(str2[i]=='c'||i==len){
                    if(cnt<2){
                        ok=0;break;
                    }
                    cnt=0;
                    ans++;
                }else{
                    cnt++;
                }
            }
            if(ok){
                printf("%d\n",ans);
            }else{
                printf("-1\n");
            }
        }
    }
    return 0;
}

1010  Jesus Is Here

        这题怎么看怎么像斐波那契数,但是解法却无关。从小到大,递推(可以理解为dp)求出每个串有多少个c,第一个c离左边多少,最后一个c离右边多少,还有长度。si很自然地就是si-2和si-1拼起来,答案就是左半部分的答案ans(i-2)+右半部分的答案ans(i-1)+横跨两边的组数,用递推出来的信息算一下就好了。

#include <iostream>     
#include <cstdio>     
#include <algorithm>     
#include <set>    
#include <vector>    
#include <string.h>    
#include <queue>  
#include <map>  
using namespace std;

#define ll long long

const int maxn = 201320;
const ll mod = 530600414;

ll tol[maxn];
ll tor[maxn];
ll cnt[maxn];
ll ans[maxn];
ll len[maxn];

int main(){

    int t;
    cin>>t;
    int cas=0;
    int n;
    
    tol[3]=1;    tor[3]=3;    cnt[3]=1;    len[3]=3;
    tol[4]=3;    tor[4]=3;    cnt[4]=1;    len[4]=5;
    //
    //ans[3]=1;    ans[4]=1;
    for(int i=5;i<=201314;i++){
        cnt[i]=cnt[i-2]+cnt[i-1];
        cnt[i]%=mod;
        tol[i]=tol[i-2]+tol[i-1]+cnt[i-1]*len[i-2];
        tol[i]%=mod;
        tor[i]=tor[i-1]+tor[i-2]+cnt[i-2]*len[i-1];
        tor[i]%=mod;
        len[i]=len[i-2]+len[i-1];
        len[i]%=mod;
        //
        ans[i]=ans[i-1]+ans[i-2];
        ans[i]+=tor[i-2]*cnt[i-1];
        ans[i]+=tol[i-1]*cnt[i-2];
        ans[i]%=mod;
        ll tmp = cnt[i-2]*cnt[i-1];
        tmp%=mod;
        ans[i]+=mod;
        ans[i]-=tmp;
        ans[i]%=mod;
    }
    ans[3]=1;    ans[4]=1;
    while(t--){
        
        cas++;
        scanf("%d",&n);
        printf("Case #%d: %I64d\n",cas,ans[n]);
    }
    
    return 0;
}

1003 Minimum Cut

        求一个无向图的最小割,必须恰好包含给出的生成树的一条边。做法是以生成树为骨架,多出来边uv,就把u-v在生成树上的路径上所有边加上权1,到最后最小边权就是答案。用离线LCA算法+打标实现。到最后dfs一次读取标记的信息,得到每条边的权,找出最小值即可。唉,这个处理方法前几天CF做过的,而且是自己想出的,比赛时居然卡题了,逗比如我。。。

#include <iostream>   
#include <cstdio>   
#include <algorithm>   
#include <set>  
#include <vector>  
#include <string.h>  
using namespace std;   
  
#define ll long long  
  
const int mod=1000000007;  
ll INF=1000000000000000000LL;  

#define maxn 20010    

//输入挂 
void scanf_(int &num){  
  char in;  
  bool neg=false;  
  while(((in=getchar()) > '9' || in<'0') && in!='-') ;  
  if(in=='-')  
  {  
    neg=true;  
    while((in=getchar()) >'9' || in<'0');  
  }  
  num=in-'0';  
  while(in=getchar(),in>='0'&&in<='9')  
    num*=10,num+=in-'0';  
  if(neg)  
    num=0-num;  
}

int n,m;  
int tote;  
int a[maxn];  
int b[maxn];  

int res[maxn];  
int cnt[maxn]; 

int head[maxn];
int pre[maxn<<1];
int to[maxn<<1];

void add(int x,int y){   
    to[tote]=y;    
    pre[tote]=head[x];    
    head[x]=tote++;    
}    

bool vis[maxn];    

int ans;  

//这个dfs为了读取标记信息。 
void dfs2(int k){  
	vis[k]=1;
    cnt[k]+=res[k];  
    for(int i=head[k];~i;i=pre[i]){    
        int x=to[i];
        if(vis[x])continue;
		dfs2(x);  
        cnt[k]+=cnt[x];  
    }  
    if(k!=1)ans=min(ans,cnt[k]);
}   

int ff[maxn];

int _find(int u){
	if(ff[u]==u)return u;
	int res=_find(ff[u]);
	return res;
}

void _union(int a,int b){	//把a并到b上 
	int fa=_find(a);
	int fb=_find(b);
	ff[a]=b;
}

//询问有关 
const int maxm=200010;
int qhead[maxn];
int qpre[maxm<<1];
int qto[maxm<<1];
int totq;
void qadd(int x,int y){   
    qto[totq]=y;    
    qpre[totq]=qhead[x];    
    qhead[x]=totq++;    
}    

bool finish[maxn];

//离线LCA 
void LCA(int u){
	vis[u]=1;
	for(int i=head[u];~i;i=pre[i]){
		int v=to[i];
		if(vis[v])continue;
		LCA(v);
		_union(v,u);
	}
	finish[u]=1;
	//解决关于u的问题。
	for(int i=qhead[u];~i;i=qpre[i]){
		int v=qto[i];
		if(finish[v]){
			int lca=_find(v);
			if(u!=lca){  
                res[u]++;  
                res[lca]--;  
            }  
            if(v!=lca){  
                res[v]++;  
                res[lca]--;  
            }
		}
	} 
}


void init(){
    memset(head,-1,sizeof(head));
    memset(cnt,0,sizeof(cnt));
    memset(res,0,sizeof(res));
    memset(finish,0,sizeof(finish));
    memset(qhead,-1,sizeof(qhead));
    memset(vis,0,sizeof(vis));
    tote=0;
    totq=0;
	//
	for(int i=1;i<=n;i++){
		ff[i]=i;
	}
}  

int main(){  
    
    int t;
    cin>>t;
    int cas=0;
    while(t--){
        cas++;
        
        cin>>n>>m;  
		init();
        for(int i=1;i<n;i++){  
            scanf_(a[i]);
            scanf_(b[i]);
            add(a[i],b[i]);
            add(b[i],a[i]);
        } 
        
        ans=1000000000;
        for(int i=n;i<=m;i++){   
            int a,b;
            scanf_(a);
            scanf_(b);
            qadd(a,b);
            qadd(b,a);
        }  
        
        
        memset(vis,0,sizeof(vis));
        LCA(1);
		memset(vis,0,sizeof(vis));

        dfs2(1);  
        printf("Case #%d: ",cas);
        cout<<ans+1<<endl;  
    }  
    return 0;  
}  

1002  Best Solver

        这题待补。。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值