【题解】 2015 ACM-ICPC Asia Regional Shenyang Online (3+1)

【1006】 FangFang (暴力枚举)

Fang Fang

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 871    Accepted Submission(s): 364


Problem Description
Fang Fang says she wants to be remembered.
I promise her. We define the sequence  F  of strings.
F0 = f",
F1 = ff",
F2 = cff",
Fn = Fn1 + f", for n > 2
Write down a serenade as a lowercase string  S  in a circle, in a loop that never ends.
Spell the serenade using the minimum number of strings in  F , or nothing could be done but put her away in cold wilderness.
 

Input
An positive integer  T , indicating there are  T  test cases.
Following are  T  lines, each line contains an string  S  as introduced above.
The total length of strings for all test cases would not be larger than  106 .
 

Output
The output contains exactly  T  lines.
For each test case, if one can not spell the serenade by using the strings in  F , output  1 . Otherwise, output the minimum number of strings in  F  to split  S according to aforementioned rules. Repetitive strings should be counted repeatedly.
 

Sample Input
  
  
8 ffcfffcffcff cffcfff cffcff cffcf ffffcffcfff cffcfffcffffcfffff cff cffc
 

Sample Output
  
  
Case #1: 3 Case #2: 2 Case #3: 2 Case #4: -1 Case #5: 2 Case #6: 4 Case #7: 1 Case #8: -1
Hint
Shift the string in the first test case, we will get the string "cffffcfffcff" and it can be split into "cffff", "cfff" and "cff".
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5467  5466  5463  5462  5461 
 


题意是找最小的划分 子串在题中已给出 f ff cff cfff cf4 cf5 cf6 cfn 这样只要暴力判两个c之间f的数目即可 如果存在两个c之间f小于2 说明不可划分 否则一定会划分成c的数量个区间 也就是划分的最小数量为c的数量 另外 如果没c 就划分成len/2+len%2 即全划ff或f

额外需要注意的是有空串和其余字符还有串是环串 首尾连在一起的。。。


代码如下:

#include <bits/stdc++.h>

using namespace std;

char str[1111111];
int pos[1111111];
int tp;

int main()
{
    int t,i,z,cnt,f,len;
    scanf("%d",&t);
    getchar();
    for(z = 1; z <= t; ++z)
    {
        gets(str);
        tp = 0;
        f = 1;
        for(i = 0; str[i]; ++i)
        {
            if(str[i] == 'c') pos[tp++] = i;//记录每个c的位置
            else if(str[i] != 'f') f = 0;//有其余字符
        }

        len = strlen(str);
        printf("Case #%d: ",z);
        if(!f) puts("-1");//有其余字符
        else if(tp == 0)//没有c
        {
            printf("%d\n",len/2+len%2);
        }
        else
        {
            for(i = 0; i < tp-1; ++i)
            {
                if(pos[i+1]-pos[i]-1 < 2)//两个c之间f数量小于2
                {
                    f = 0;
                    break;
                }
            }
            if(len-1-pos[tp-1]+pos[0] < 2) f = 0;//特判第一个c和最后一个 因为是成环切割
            if(f)
            {
                printf("%d\n",tp);
            }else puts("-1");
        }
    }
    return 0;
}

【1010】 Jesus Is Here (斐波那契+推公式)

Jesus Is Here

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 360    Accepted Submission(s): 255


Problem Description
I've sent Fang Fang around 201314 text messages in almost 5 years. Why can't she make sense of what I mean?
``But Jesus is here!" the priest intoned. ``Show me your messages."
Fine, the first message is  s1=c"  and the second one is  s2=ff" .
The  i -th message is  si=si2+si1  afterwards. Let me give you some examples.
s3=cff" s4=ffcff"  and  s5=cffffcff" .

``I found the  i -th message's utterly charming," Jesus said.
``Look at the fifth message".  s5=cffffcff"  and two  cff"  appear in it.
The distance between the first  cff"  and the second one we said, is  5 .
``You are right, my friend," Jesus said. ``Love is patient, love is kind.
It does not envy, it does not boast, it is not proud. It does not dishonor others, it is not self-seeking, it is not easily angered, it keeps no record of wrongs.
Love does not delight in evil but rejoices with the truth.
It always protects, always trusts, always hopes, always perseveres."

Listen - look at him in the eye. I will find you, and count the sum of distance between each two different  cff"  as substrings of the message.
 

Input
An integer  T (1T100) , indicating there are  T  test cases.
Following  T  lines, each line contain an integer  n (3n201314) , as the identifier of message.
 

Output
The output contains exactly  T  lines.
Each line contains an integer equaling to:
i<j:sn[i..i+2]=sn[j..j+2]=cff"(ji) mod 530600414,

where  sn  as a string corresponding to the  n -th message.
 

Sample Input
  
  
9 5 6 7 8 113 1205 199312 199401 201314
 

Sample Output
  
  
Case #1: 5 Case #2: 16 Case #3: 88 Case #4: 352 Case #5: 318505405 Case #6: 391786781 Case #7: 133875314 Case #8: 83347132 Case #9: 16520782
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5467  5466  5463  5462  5461 
 

递推公式。。。

首先有这么几个数组 

pre //首个c到之后c的距离和 

post //最后一个c到之前c的距离和

cnt //点数

ans //答案(任意两个c距离和)

f //最大两个c的间距

1 c

2 ff

3 cff

4 ffcff

5 cffffcff

6 ffcffcffffcff

7 cffffcffffcffcffffcff

这是前几项 很容易推出 

cnt[i] = cnt[i-2] + cnt[i-1] //点数

f[i] = f[i-2] + f[i-1] + ((i%2 == 0)? 3: 5) //c 最大间距

然后发现 如果有pre 跟post之后 ans也可推出

ans[i] = post[i-2]*cnt[i-1]+pre[i-1]*cnt[i-2]+x*cnt[i-2]*cnt[i-1]+ans[i-1]+ans[i-2]; // x :两串合并后中间cffffc f数量 跟当前串奇偶有关 x = ((i%2 == 0)? 3: 5)

ans = 前串末c到之前所有c的距离和 * 后串c个数 + 后串首c到之后所有c的距离和*前串c的个数 + 中间f数量*两串c数积 + 两串各自c距离和

原理: 组成新串后 后串任意c到前串每个c的距离等于 前串末c到之前每个c距离+生成新串中间新加f数*前串点数

前串c到后串同理 之后再加上两串各自c距离和即可

这样只需要再推出pre跟post即可

pre[i] = x*cnt[i-1]+pre[i-1]+pre[i-2]+f[i-2]*cnt[i-1] //新串首c到之后c的距离和 继承前后串距离和-pre[i-2,i-1] 然后到后串经过 cnt[i-1]*f[i-2] 和 x*cnt[i-1]

post[i] = x*cnt[i-2]+post[i-1]+post[i-2]+f[i-1]*cnt[i-2] //同上

递推结束 O(1)输出答案即可 注意推到过程中步步取余。。烦= =


代码如下:

#include <bits/stdc++.h>
#define mod 530600414
#define ll long long

using namespace std;

ll f[201316];
ll cnt[201316];
ll ans[201316],pre[201316],post[201316];

int main()
{
    int i,t,n,x;
    cnt[3] = 1;
    cnt[4] = 1;
    f[3] = 0;
    f[4] = 0;
    ans[3] = ans[4] = 0;
    pre[3] = pre[4] = post[3] = post[4] = 0;

    for(i = 5; i <= 201314; ++i)
    {
        cnt[i] = (cnt[i-1]+cnt[i-2])%mod;
<span style="white-space:pre">	</span>x = i&1? 5: 3;
        f[i] = (f[i-1]+f[i-2]+x)%mod;
        pre[i] = (((x*cnt[i-1]%mod+pre[i-1])%mod+pre[i-2])%mod+f[i-2]*cnt[i-1]%mod)%mod;
        post[i] = (((x*cnt[i-2]%mod+post[i-1])%mod+post[i-2])%mod+f[i-1]*cnt[i-2]%mod)%mod;
        ans[i] = (((post[i-2]*cnt[i-1]%mod+pre[i-1]*cnt[i-2]%mod)%mod+x*cnt[i-2]*cnt[i-1]%mod)%mod+ans[i-1]+ans[i-2])%mod;
    }

    scanf("%d",&t);
    for(int z = 1; z <= t; ++z)
    {
        scanf("%d",&n);
        printf("Case #%d: %I64d\n",z,ans[n]);
    }
    return 0;
}

【1012】 Largest Point (sort)

Largest Point

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1005    Accepted Submission(s): 397


Problem Description
Given the sequence  A  with  n  integers  t1,t2,,tn . Given the integral coefficients  a  and  b . The fact that select two elements  ti  and  tj  of  A  and  ij  to maximize the value of  at2i+btj , becomes the largest point.
 

Input
An positive integer  T , indicating there are  T  test cases.
For each test case, the first line contains three integers corresponding to  n (2n5×106), a (0|a|106)  and  b (0|b|106) . The second line contains  n integers  t1,t2,,tn  where  0|ti|106  for  1in .

The sum of  n  for all cases would not be larger than  5×106 .
 

Output
The output contains exactly  T  lines.
For each test case, you should output the maximum value of  at2i+btj .
 

Sample Input
  
  
2 3 2 1 1 2 3 5 -1 0 -3 -3 0 3 3
 

Sample Output
  
  
Case #1: 20 Case #2: 0
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5467  5466  5463  5462  5461 
 

这题我做麻烦了 简单做法就是结构体 存放每个数的a*t1^2跟 b*t2 和这数下标

两数组排序后直接去第一个判断下标是否一样 一样就比较a取最大*b取次大跟a取次打b最大 输出最大即可

我做的是不断判断。。。

算是个教训 两种都贴上吧


代码如下:

//渣法。。四个判断。。。
#include <bits/stdc++.h>
#define ll long long
#define mx 2000000
#define fwrite() freopen("../out.out","r",stdout)
#define fread() freopen("../in.in","w",stdin)

using namespace std;

ll a,b;
vector <ll> v;

ll gt(ll t1,ll t2)
{
    return a*t1*t1+b*t2;
}

int main()
{
    //fread();
    //fwrite();
    int n,i,t,sz,z;
    vector<ll>::iterator it,tmp;
    ll t1,t2,x,ans;
    scanf("%d",&t);
    for(z = 1; z <= t; ++z)
    {
        v.clear();
        scanf("%d %I64d %I64d",&n,&a,&b);

        for(i = 0; i < n; ++i)
        {
            scanf("%I64d",&x);
            v.push_back(x);
        }
        sort(v.begin(),v.end());

        it = lower_bound(v.begin(),v.end(),0);
        sz = v.size();

        if(a < 0 && b < 0)//- -
        {
            tmp = it;
            tmp--;
            if(it == v.begin() || tmp == v.begin())
            {
                ans = max(gt(v[1],v[0]),gt(v[0],v[1]));
            }
            else ans = max(gt(*it,v[0]),gt(*tmp,v[0]));
        }
        else if(a < 0 && b >= 0)//- +
        {
            tmp = it;
            tmp++;
            if(tmp == v.end())
            {
                ans = max(gt(v[sz-1],v[sz-2]),gt(v[sz-2],v[sz-1]));
            }
            else if(it == v.begin())
            {
                ans = gt(v[0],v[sz-1]);
            }
            else
            {
                tmp = it--;
                ans = max(gt(*it,v[sz-1]),gt(*tmp,v[sz-1]));
            }
        }
        else if(a >= 0 && b <= 0)//+ -
        {
            ans = max(gt(v[0],v[1]),gt(v[sz-1],v[0]));
        }
        else//+ +
        {
            ans = gt(v[0],v[sz-1]);
            ans = max(ans,gt(v[sz-1],v[sz-2]));
            ans = max(ans,gt(v[sz-2],v[sz-1]));
        }
        printf("Case #%d: %I64d\n",z,ans);
    }
    return 0;
}


//排序输出。。。慢 慢又怎样 好想啊…………if渣法卡半天TOT
#include <bits/stdc++.h>
#define ll long long
#define mx 2000000
#define fwrite() freopen("../out.out","r",stdout)
#define fread() freopen("../in.in","w",stdin)

using namespace std;

struct Mult
{
    ll ans;
    int id;
    bool operator < (const struct Mult a)const
    {
        return ans == a.ans? id < a.id : ans > a.ans;
    }
};

Mult mla[6666666],mlb[6666666];
ll a,b;

int main()
{
    //fread();
    //fwrite();
    int n,i,t,z;
    ll x;
    scanf("%d",&t);
    for(z = 1; z <= t; ++z)
    {
        scanf("%d %I64d %I64d",&n,&a,&b);

        for(i = 0; i < n; ++i)
        {
            scanf("%I64d",&x);
            mla[i].ans = a*x*x;
            mlb[i].ans = b*x;
            mla[i].id = mlb[i].id = i;
        }
        sort(mla,mla+n);
        sort(mlb,mlb+n);
        printf("Case #%d: %I64d\n",z,mla[0].id != mlb[0].id? (mla[0].ans+mlb[0].ans): max(mla[0].ans+mlb[1].ans,mla[1].ans+mlb[0].ans));
    }
    return 0;
}

【1003】 Minimum Cut (LCA+搜)

Minimum Cut

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 860    Accepted Submission(s): 372


Problem Description
Given a simple unweighted graph  G  (an undirected graph containing no loops nor multiple edges) with  n  nodes and  m  edges. Let  T  be a spanning tree of  G .
We say that a cut in  G  respects  T  if it cuts just one edges of  T .

Since love needs good faith and hypocrisy return for only grief, you should find the minimum cut of graph  G  respecting the given spanning tree  T .
 

Input
The input contains several test cases.
The first line of the input is a single integer  t (1t5)  which is the number of test cases.
Then  t  test cases follow.

Each test case contains several lines.
The first line contains two integers  n (2n20000)  and  m (n1m200000) .
The following  n1  lines describe the spanning tree  T  and each of them contains two integers  u  and  v  corresponding to an edge.
Next  mn+1  lines describe the undirected graph  G  and each of them contains two integers  u  and  v  corresponding to an edge which is not in the spanning tree  T .
 

Output
For each test case, you should output the minimum cut of graph  G  respecting the given spanning tree  T .
 

Sample Input
  
  
1 4 5 1 2 2 3 3 4 1 3 1 4
 

Sample Output
  
  
Case #1: 2
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5467  5466  5463  5462  5460 
 

找最小割边 即让图不连通需要出去的最少边数 并且满足一条边在树上

建图方法是先建T树 然后再T树上加m-n+1条边构成G图

在树上每加一条边u,v u跟v的不同子树间都连一条边 也就是u,v一直向上到LCA(u,v)度数++ 这样找最小度数的节点就行 可惜当时渣到不会LCA 有个板子也好……


代码如下:

#include <bits/stdc++.h>

using namespace std;
#define INF 0x3f3f3f3f
const int MAXN = 81000;//点数的最大值
const int MAXM = 604000;//边数的最大值

int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
    int mm[2*MAXN];
    int dp[2*MAXN][20];//最小值对应的下标
    void init(int n)
    {
        mm[0] = -1;
        for(int i = 1;i <= n;i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1; j <= mm[n];j++)
            for(int i = 1; i + (1<<j) - 1 <= n; i++)
                dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)//查询[a,b]之间最小值的下标
    {
        if(a > b)swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
};

struct Edge
{
    int v,next;
};

Edge eg[MAXM];
int head[MAXN],tp;
int cnt;
int len[MAXN],fa[MAXN];
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
ST st;
void dfs(int u,int pre,int dep)
{
    fa[u]=pre;
    F[++cnt] = u;
    rmq[cnt] = dep;
    P[u] = cnt;
    for(int i = head[u];i != -1;i = eg[i].next)
    {
        int v = eg[i].v;
        if(v == pre)continue;
        dfs(v,u,dep+1);
        F[++cnt] = u;
        rmq[cnt] = dep;
    }
}
void LCA_init(int root,int node_num)//查询LCA前的初始化
{
    cnt = 0;
    dfs(root,root,0);
    st.init(2*node_num-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
    return F[st.query(P[u],P[v])];
}

void Add(int u,int v)
{
    eg[tp].v = v;
    eg[tp].next = head[u];
    head[u] = tp++;
}
int dp[MAXN];

void cal(int u,int pre)//搜最小度数
{
    for(int i = head[u]; ~i; i = eg[i].next)
    {
        int v = eg[i].v;
        if(v == pre) continue;
        cal(v,u);
        dp[u] += dp[v];
    }
}

int main()
{
    int t,n,u,v,m,ans;

    scanf("%d",&t);
    for(int z = 1; z <= t; ++z)
    {
        scanf("%d %d",&n,&m);
        memset(head,-1,sizeof(head));
        tp = 0;
        for(int i = 0; i < n-1; ++i)
        {
            scanf("%d %d",&u,&v);
            Add(u,v);
            Add(v,u);
        }
        LCA_init(1,n);
        memset(dp,0,sizeof(dp));
        for(int i = n; i <= m; ++i)
        {
            scanf("%d %d",&u,&v);
            dp[u]++;
            dp[v]++;
            dp[query_lca(u,v)] -= 2;
        }
        cal(1,0);
        ans = INF;
        for(int i = 2; i <= n; ++i)
            ans = min(ans,dp[i]+1);
        printf("Case #%d: %d\n",z,ans);
    }

    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值