【2016常州一中夏令营Day1】

Problem 1. suffix
给定一个单词,如果该单词以 er、 ly 或者 ing 后缀结尾,则删除该后缀(题目保证删除后缀后的单词长度不为 0),否则不进行任何操作。
Input
输入一行,包含一个单词(单词中间没有空格,每个单词最大长度为 32)
Output
输出按照题目要求处理后的单词。
Example
suffix.in          suffix.out
referer          refer
Scoring
? 对于 40% 的数据,单词最大长度不超过 5。

题解

无可奉告

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int len;
char s[5005];

int main()
{
    int i,j;
    freopen("suffix.in","r",stdin);
    freopen("suffix.out","w",stdout);
    scanf("%s",s);
    len=strlen(s);
    if((s[len-1]==‘r‘&&s[len-2]==‘e‘)||(s[len-1]==‘y‘&&s[len-2]==‘l‘))
    {
        for(i=0;i<=len-3;i++) printf("%c",s[i]);
        goto hhh;
    }
    if(s[len-1]==‘g‘&&s[len-2]==‘n‘&&s[len-3]==‘i‘)
    {
        for(i=0;i<=len-4;i++) printf("%c",s[i]);
        goto hhh;
    }
    printf("%s",s);
    hhh:
    fclose(stdin);
    fclose(stdout);
    return 0;

}

Problem 2. weight
设有 1g, 2g, 3g, 5g, 10g, 20g 的砝码各若干枚(其总重 100, 000),要求:计算用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况。
Input
一行,包括六个正整数 a1, a2, a3, a4, a5, a6,表示 1g 砝码有 a1 个, 2g 砝码有 a2 个,……, 20g 砝码有 a6 个。相邻两个整数之间用单个空格隔开。
Output
以“Total=N”的形式输出,其中 N 为可以称出的不同重量的个数。
Example
weight.in          weight.out
1 1 0 0 0 0      Total=3
Explanation
样例给出的砝码可以称出 1g, 2g, 3g 三种不同的重量。
Scoring
? 对于 20% 的数据,砝码总个数不超过 20。
? 对于 40% 的数据,砝码总个数不超过 800。

题解

二进制拆分+背包

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int ans,cnt;
int a[7],w[200005],m[7]={0,1,2,3,5,10,20};
bool f[200005];

int main()
{
    int i,j,t;
    freopen("weight.in","r",stdin);
    freopen("weight.out","w",stdout);
    for(i=1;i<=6;i++)
    {
        scanf("%d",&a[i]);
        t=0;
        while(a[i]-(1<<t)>=0)
        {
            a[i]=a[i]-(1<<t);
            w[++cnt]=m[i]*(1<<t);
            t++;
        }
        if(a[i]!=0) w[++cnt]=m[i]*a[i];

    }
    f[0]=1;
    for(i=1;i<=cnt;i++)
      for(j=100000;j>=1;j--)
        if(j-w[i]>=0) f[j]|=f[j-w[i]];

    for (i=1;i<=100000;i++) ans+=f[i];
    printf("Total=%d\n", ans);
    return 0;
}

二进制拆分思想优化暴力也能过。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int tot,sum,now,pre,cnt;
int a[11],num[7]={0,1,2,3,5,10,20},n[100005];
bool u[100005];

bool check(int x)
{
    int i;
    for(i=7-x;i<=6;i++)
        if(a[i]) return false;
    return true;
}
bool pd(int x)
{
    int i;
    for(i=1;i<=x;i++)
        if(!a[i]) return false;
    return true;
}
int main()
{
    int i,j,k,temp,beg,b,tt;
    bool flag;
    freopen("weight.in","r",stdin);
    freopen("weight.out","w",stdout);
    for(i=1;i<=6;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i]*num[i];
        if(a[i]) cnt++;
    }
    if(check(6-cnt))
    {
        tot=sum;
        goto hhh;
    }
    for(i=1;i<=6;i++)
        if(!pd(i)) {pre=i-1;break;}
    b=0;
    for(i=1;i<=6;i++) if(!a[i]) break;
    for(j=i;j<=6;j++) if(a[j]){b=j;break;}
    sum=0;
    for(i=1;i<=pre;i++) sum+=a[i]*num[i];
    for(i=1;i<=sum;i++)
    {
        n[i]=i;
        u[i]=true;
    }
    tot=sum;
    if(!b) goto hhh;
    for(i=b;i<=6;i++)
    if(a[i])
    {
        beg=tot;
        for(j=0;j<=beg;j++)
        {
            temp=n[j]+num[i];
            if(!u[temp])
            {
                u[temp]=true;
                n[++tot]=temp;
            }
        }
        tt=tot;
        for(k=2;k<=a[i];k++)
        {
            for(j=beg;j<=tt;j++)
            {
                temp=n[j]+num[i];
                if(!u[temp])
                {
                    u[temp]=true;
                    n[++tot]=temp;
                }
            }
             beg=tt;tt=tot;
        }
    }
    hhh:;
    printf("Total=%d",tot);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

Problem 3. hopscotch
给定一个 n m 列的方格,每个格子里有一个正整数 a, 1 a k, k n ? m
假设你当前时刻站在 (i, j) 这个格子里,你想要移动到 (x, y),那必须满足以下三个条件
1: i < x
2: j < y
3:第 i 行第 j 列格子里的数不等于第 x 行第 y 列格子里的数
求从 (1, 1) 移动到 (n, m) 的不同的方案数
Input
第一行三个数 n, m, k
接下来 n 行每行 m 个正整数,表示每个格子里的数
Output
一行一个数,表示从 (1, 1) 移动到 (n, m) 的不同的方案数,模 109 + 7
Example
hopscotch.in           hopscotch.out
4 4 4                    5
1 1 1 1
1 3 2 1
1 2 4 1
1 1 1 1
Scoring
? 对于 20% 的数据, n, m 20。
? 对于 60% 的数据, n, m 100。
? 对于 100% 的数据, n, m 750。

题解 by TonyFang

http://tonyfang.is-programmer.com/posts/205063.html

首先我们用一个动态开点的权值线段树的东西。

什么是动态开点?

本来线段树都是一开始build一下建完了,现在是边插入边建

由于线段树插入一个数,其他的数的形态并不需要改变,所以就行啦。

大概insert的最重要的步骤如下(动态开节点)

if(! root) (还没有开节点) root=++tot; (新开节点)

具体可以见代码呀

这题dp是O(n^4)挺好想出来的,然后用减法原理变成一个类似于二维前缀和减去一些相等的dp值

那么用动态开点权值线段树就恰好能解决。时间复杂度O(n^2 logn)

//by TonyFang
# include <stdio.h>
# include <stdlib.h>

using namespace std;

int n, m, k;
long long f[760][760], s[760][760];
int a[760][760];
const int M=760*760*4, MOD = 1e9+7;
int lc[7000010], rc[7000010], num[7000010], root[M], tot=0;

inline void insert(int &rt, int l, int r, int pos, int val) {
    if(!rt) rt=++tot;
    if(l == r && l == pos) {
        num[rt] = num[rt] + val;
        num[rt] %= MOD;
        return ;
    }
    int mid = l+r >> 1;
    if(pos <= mid) insert(lc[rt], l, mid, pos, val);
    else insert(rc[rt], mid+1, r, pos, val);
    num[rt] = num[lc[rt]] + num[rc[rt]];
    num[rt] %= MOD;
}

inline int query(int rt, int l, int r, int pos) {
    if(!rt) return 0;
    if(r <= pos) return num[rt];
    int mid = (l+r) >> 1, anss=0;
    if(lc[rt]) anss = (anss + query(lc[rt], l, mid, pos)) % MOD;
    if(rc[rt] && pos >= mid+1) anss = (anss + query(rc[rt], mid+1, r, pos)) % MOD;
    return anss;
}

int main() {
    freopen("hopscotch.in", "r", stdin);
    freopen("hopscotch.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &k);
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=m; ++j) scanf("%d", &a[i][j]);
    f[1][1] = 1;
    for (int i=1; i<=n; ++i)
        s[1][i] = s[i][1] = 1;
    insert(root[a[1][1]], 1, m, 1, 1);
    for (int i=2; i<=n; ++i) {
        for (int j=2; j<=m; ++j) {
            f[i][j] = s[i-1][j-1];
            //printf("i=%d, j=%d\n", i, j);
            // sub
            int gg = query(root[a[i][j]], 1, m, j-1);
            //printf("i=%d, j=%d, s[i-1][j-1]=%d, sub=%d\n", i, j, s[i-1][j-1], gg);
            //printf("%d\n", gg);
            f[i][j] = ((f[i][j] - gg) % MOD + MOD) % MOD;
            //printf("f[i][j]=%d\n",f[i][j]);
            s[i][j] = f[i][j];
            s[i][j] = (s[i][j] + s[i-1][j]) % MOD;
            s[i][j] = (s[i][j] + s[i][j-1]) % MOD;
            s[i][j] = ((s[i][j] - s[i-1][j-1]) % MOD + MOD) % MOD;
        }
        for (int j=2; j<=m; ++j)
            insert(root[a[i][j]], 1, m, j, f[i][j]);
    }

    printf("%d\n", f[n][m]);
    return 0;
}

Problem 4. alphabet
给定一棵 n 个点的树,树上每个节点代表一个小写字母,询问一个字符串 S 是否在树上出现过?
字符串 S 出现过即表示存在两个点 u, vu v 的最短路径上依次连接所有点上的字母恰好是 S
Input
第一行一个数 T 表示数据组数
每组数据先输入一个数 n 表示这棵树有 n 个节点
接下来 n ? 1 行每行两个数 u, v,表示 u, v 之间存在一条无向边
下一行包含 n 个字符,表示每个节点上的字符
下一行包含一个字符串 S
Output
对于每组数据”Case #k: ”, k 为测试点编号,如果出现过则输出 Find,否则输出 Impossible
Example
alphabet.in          alphabet.out
2                      Case #1: Find
7                      Case #2: Impossible
1 2
2 3
2 4
1 5
5 6
6 7
abcdefg
dbaefg
5
1 2
2 3
2 4
4 5
abcxy
yxbac
Scoring
? 对于 20% 的数据, N 1000。
? 对于另外 20% 的数据, N 104,且树上有且仅有一种字母。
? 对于另外 30% 的数据, N 104,且树随机生成。
? 对于另外 30% 的数据, N 104,且树上的字母随机生成。

题解

统计起点和终点的个数,从个数少的开始暴力即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int tt,n,cas,cnt,len;
int last[1000005];
char str[1000005],ask[1000005];
bool flag,ph[1005];
struct hh
{
    int next,to;
};
hh e[1000005];

void add(int a,int b)
{
    ++cnt;
    e[cnt].to=b;
    e[cnt].next=last[a];
    last[a]=cnt;
}

void run(int x,int now)
{
    int i,j;
    if(flag) return;
    if(now==len)
    {
        flag=true;
        return;
    }
    for(i=last[x];i;i=e[i].next)
        if(str[e[i].to]==ask[now+1])
            run(e[i].to,now+1);
}

int main()
{
    int i,j,a,b,s,t;
    freopen("alphabet.in","r",stdin);
    freopen("alphabet.out","w",stdout);
    scanf("%d",&tt);
    while(tt--)
    {
        memset(last,0,sizeof(last));
        memset(ph,0,sizeof(ph));
        flag=false;cnt=0;
        scanf("%d",&n);
        for(i=1;i<=n-1;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        scanf("%s",str+1);
        scanf("%s",ask+1);

        len=strlen(ask+1);
        for(i=1;i<=n;i++)  ph[str[i]]=true;
        for(i=1;i<=len;i++)
            if(!ph[ask[i]])
            {
                cas++;
                printf("Case #%d: Impossible\n",cas);
                goto hhh;
            }

        s=t=0;
        for(i=1;i<=n;i++)
        {
            if(str[i]==ask[1]) s++;
            if(str[i]==ask[len]) t++;
        }
        if(s>t) reverse(ask+1,ask+len+1);

        for(i=1;i<=n;i++)
            if(ask[1]==str[i])
            {
                run(i,1);
                if(flag) break;
            }
        cas++;
        if(flag) printf("Case #%d: Find\n",cas);
        else printf("Case #%d: Impossible\n",cas);
        hhh:;
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

Problem 5. route
给一个 n ? m 的矩阵,矩阵的每个格子上有一个不超过 30 的非负整数。
我们定义一条合法的路线是从( 1, 1)开始只能向右和向下移动到达( n, m)的路线。
定义数列 A1, A2, A3, .., An+m?1 为一条合法路线上的序列,且 Aavg 为该数列的平均值。该路线的
价值为 (n + m ? 1) 乘上该数列的方差。
即价值的表达式为 (n + m ? 1) ∑n i=1 +m?1 (Ai ? Aavg)2。
请找一条价值最小的路线,并输出这个价值。
Input
第一行两个正整数 n, m,表示矩阵的行数和列数。
以下 n 行每行 m 个非负整数 ai,j 表示矩阵上的数。
Output
包含一个整数,最小化的路线的价值。
Example
route.in         route.out
2 2              14
1 2
3 4
Explanation
方案一: 1-3-4,平均数 Aavg = 8 3
方差 = (1 ? 8 3)2 + (3 ? 8 3)2 + (4 ? 8 3)2 = 14 3
最终答案 = (2 + 2 ? 1) ? 14 3 = 14
方案二: 1-2-4,平均数 Aavg = 7 3
方差 = (1 ? 7 3)2 + (2 ? 7 3)2 + (4 ? 7 3)2 = 14 3
最终答案 = (2 + 2 ? 1) ? 14 3 = 14
Scoring
? 对于 30% 的数据, n, m, ai,j 10。
? 对于 60% 的数据, n, m, ai,j 15。
? 对于 100% 的数据, n, m, ai,j 30。

题解

对于式子

可拆开

最后整理为

表示从 走到 和为的最小值。

考虑优化空间,可枚举,不断更新答案,于是表示从 走到 的最小值。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m,ans;
int a[55][55],f[55][55];
int main()
{
    int i,j,sum;
    freopen("route.in", "r", stdin);
    freopen("route.out", "w", stdout);
    ans=9999999;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    for(sum=0;sum<=(n+m-1)*30;sum++)
    {
        memset(f,0,sizeof(f));
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            {
                if(i==1) f[i][j]=f[i][j-1];
                else
                    if(j==1) f[i][j]=f[i-1][j];
                    else f[i][j]=min(f[i-1][j],f[i][j-1]);
                f[i][j]+=a[i][j]*a[i][j]*(n+m-1)-2*a[i][j]*sum;
            }
        ans=min(ans,f[n][m]+sum*sum);
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
时间: 2024-08-03 16:26:59

【2016常州一中夏令营Day1】的相关文章

【2016常州一中夏令营Day4】

小 W 走迷宫[问题描述]小 W 被小 M 困在了一个方格矩阵迷宫里,矩阵边界在无穷远处,我们做出如下的假设:a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上:b. 走过的格子立即塌陷无法再走第二次:c. 只能向北.东.西三个方向走.小 W 走了没多久就累坏了,他很想知道如果允许在方格矩阵上走 N 步,共有多少种不同的方案.( 开始时小 W 就在方格矩阵上的任意位置, 2 种走法只要有一步不一样,即被认为是不同的方案)[输入格式]一行输入 N.[输出格式]一行输出方案个数.[输入输

【2016常州一中夏令营Day2】

小 W 学数学[问题描述]为了测试小 W 的数学水平,果果给了小 W N 个点,问他这 N 个点能构成的三角形个数.[输入格式]第一行一个整数 N,代表点数.接下来 N 行,每行两个非负整数 X.Y,表示一个点的坐标.[输出格式]一个非负整数,即构成三角形个数.[输入输出样例]tri.in       5           0 01 02 00 11 1 tri.out       9 [数据规模]对于 20%的数据:N=3对于另外 40%的数据:保证任意 3 点不在同一直线上对于 100%的

【2016常州一中夏令营Day7】

序列(sequence)[题目描述]蛤布斯有一个序列,初始为空.它依次将 1-n 插入序列,其中 i插到当前第 ai 个数的右边 (ai=0 表示插到序列最左边).它希望你帮它求出最终序列.[输入数据]第一行一个整数 n.第二行 n 个正整数 a1~an.[输出数据]输出一行 n 个整数表示最终序列,数与数之间用一个空格隔开.[样例输入]50 1 1 0 3[样例输出]4 1 3 5 2[数据范围]对于 30%的数据,n<=1000.对于 70%的数据,n<=100000对于 100%的数据,

【2016常州一中夏令营Day3】

小 W 摆石子[问题描述]小 W 得到了一堆石子,要放在 N 条水平线与 M 条竖直线构成的网格的交点上.因为小 M 最喜欢矩形了,小 W 希望知道用 K 个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子.[输入格式]第一行三个整数 N,M,K.[输出格式]一个非负整数,即最多的满足条件的长方形数量.[输入输出样例] rectangle.in3 3 8rectangle.out5 rectangle.in7 14 86rectangle.out1398 [数据规模]对

【2016常州一中夏令营Day5】

小 W 拼图[问题描述]小 W 和小 M 一起玩拼图游戏啦~小 M 给小 M 一张 N 个点的图,有 M 条可选无向边,每条边有一个甜蜜值,小 W 要选K 条边,使得任意两点间最多有一条路径,并且选择的 K 条边甜蜜值之和最大.[输入格式]第一行三个正整数 N,M,K.接下来 M 行,每行三个正整数 A,B,C,表示 A.B 两点间有一条甜蜜值为 C 的无向边.[输出格式]一行输出最大甜蜜值之和.[输入输出样例]carpet.in 5 4 31 2 101 3 92 3 74 5 3 carpe

常州一中B.1

差不多有一个星期左右没有刷题啦>< 就随便抓了一套水了一遍 T1,T3,T4纯模拟,我就不吐槽啦 T2还有点意思,略带数学思想 这种题目以后不用慌呀,自己拿笔好好算算,总会找到规律的呀╮(╯▽╰)╭ 之后要开始刷题啦 暑假作业三天之内写完了= =好像有点快? 之后就是预习啦,五三刷起来~\(≧▽≦)/~ 当然还有oi呀..... 退役的最后一些日子里 常州一中B.1,布布扣,bubuko.com

【2016福建省夏令营Day1】数据结构

Problem 1 楼房(build.cpp/c/pas) [题目描述] 地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i]).地平线高度为0.在轮廓线长度最小的前提下,从左到右输出轮廓线. 下图为样例2. [输入格式] 第一行一个整数n,表示矩形个数. 以下n行,每行3个整数h[i],l[i],r[i]表示第i个矩形. [输出格式] 第一行一个整数m,表示节点个数. 以下m行,每行

2016.8.25 NOIP2012 day1 解题报告

考试总结: 1.  显然第一道送分题,我差一点直接打表来对拍了,后来发现我们的pdf有问题不能复制,并且我没有YJQ大神那样足够的时间每道题都对拍,就只能试过样例就遁,(其实这种密码我玩过,密码学入门密码,当时好像叫凯撒密码233):对了,ASCII的掌握也很重要,我之前一直以为大写在小写后面啧.(之间漏掉过大于以后减的步骤,这种简单题还是做少了居然耗了30min,以后好好检查争取一次过): 2.  这道题我拿到的第一反应就是贪心,马上想了一个贪心规则但自己总觉得是错的,花了很长的时间举反例举不

2015北大夏令营day1 B:An Idea of Mr. A

题意:给定一个范围l,r计算i,j(i<j)属于这个范围内的gcd(2^(2^i)+1,2^(2^j)+1)的总和. 思路:费马数的应用,让我惊呆的是当年居然有123个人会做,我tm毛都不会.. 其实就是任意两个费马数都互质,就这样.. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #