暑训day1解题报告

A - Painting the sticks

因为不能覆盖涂/涂两次,所以就数数有几个三个一块儿就行了。

#include<cstdio>
int a[100],ans ;
int main()
{
    int n , t = 0 ;
    while (scanf("%d",&n)!=EOF) {
       for (int i=1; i<=n; ++i) scanf("%d",a+i);
       ans = 0 ;
       for (int i=1; i<=n ; ++i) if (a[i]!=a[i-1]) ++ans ;
       ans = ans /3 + ( ans % 3>0)  ;
       ++t ;
       printf("Case %d: %d\n",t,ans) ;
    }
}

B - "Ray, Pass me the dishes!"

线段树,没过,不知道是想错了还是写呲毛了。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

/**
 * 待处理序列A从1到N
 * min对应的序列是前缀和序列右移一位
 */
const int  MaxN = 500000;
#define left  first
#define right second
long long A[MaxN];
struct Range:pair<int,int>{
    Range(int a=0,int b=0){
        left  = a;
        right = b;
    }
    long long sum(){
        return A[right]-A[left-1];
    }
};
struct node {
    int l,r,maxPos,minPos;
    node(int x=0){l=r=maxPos=minPos=x;}
    long long ans(){return A[l]-A[r-1];}
    long max(){return A[maxPos];}
    long min(){return A[minPos-1];}
};
struct SegmentTree
{
    #define MaxSegmentLength 500000
    const int root;
    SegmentTree():root(1){}
    node data[4*MaxSegmentLength];
    void newNode(int p,int x){data[p]=node(x);}
    void maintain(int p){
        int lch= p*2,rch= p*2+1,t=0;

        t=(data[lch].ans()>data[rch].ans())?lch:rch;

        data[p].l=data[t].l;
        data[p].r=data[t].r;

        if(data[p].ans()<(data[rch].max()-data[lch].min())){
            data[p].l=data[lch].minPos;
            data[p].r=data[rch].maxPos;
        }

        data[p].maxPos = (data[lch].max()>data[rch].max())?
                            data[lch].maxPos:
                            data[rch].maxPos;
        data[p].minPos = (data[lch].min()<data[rch].min())?
                            data[lch].minPos:
                            data[rch].minPos;
    }
    void build(int x,int y,int p){
        if (x==y)
            newNode(p,x);
        else {
            int mid=(x+y)/2;
            build(x    ,mid,p*2  );
            build(mid+1,y  ,p*2+1);
            maintain(p);
        }
    }
    int queryMax(int x,int y,int l,int r,int p)
    {
        //cout<<"QueryMax  ("<<x<<‘,‘<<y<<")  ["<<l<<‘,‘<<r<<"] @"<<p<<endl;
        if (x==l && y==r) return data[p].maxPos;
        int mid = (l+r)/2,LPos,RPos;
        //cout<<"        "<<l<<‘,‘<<mid<<‘|‘<<mid+1<<‘,‘<<r<<endl;
        if (y<=mid) return queryMax(x,y,l    ,mid,p*2  );
        if (x >mid) return queryMax(x,y,mid+1,r  ,p*2+1);
            LPos=queryMax(x    ,mid,l    ,mid,p*2);
            RPos=queryMax(mid+1,y  ,mid+1,r  ,p*2+1);
            //cout<<"     max(L,R)"<<LPos<<‘ ‘<<RPos<<endl;
            return A[LPos]>A[RPos] ? LPos : RPos;
    }
    int queryMin(int x,int y,int l,int r,int p)
    {
        //cout<<"QueryMin  ("<<x<<‘,‘<<y<<")  ["<<l<<‘,‘<<r<<"] @"<<p<<endl;
        if (x==l && y==r) return data[p].minPos;
        int mid = (l+r)/2,LPos,RPos;
        //cout<<"        "<<l<<‘,‘<<mid<<‘|‘<<mid+1<<‘,‘<<r<<endl;
        if (y<=mid) return queryMin(x,y,l    ,mid,p*2  );
        if (x >mid) return queryMin(x,y,mid+1,r  ,p*2+1);
            LPos=queryMin(x    ,mid,l    ,mid,p*2);
            RPos=queryMin(mid+1,y  ,mid+1,r  ,p*2+1);
            //cout<<"     min(L,R)"<<LPos<<‘ ‘<<RPos<<endl;
            return A[LPos-1]<A[RPos-1] ? LPos : RPos;
    }
    Range query(int x,int y,int l,int r,int p)
    {
        //cout<<"Query  ("<<x<<‘,‘<<y<<")  ["<<l<<‘,‘<<r<<"] @"<<p<<endl;
        if (x==l && y==r) return Range(data[p].l,data[p].r);
        int mid = (l+r)/2 ;
        //cout<<"        "<<l<<‘,‘<<mid<<‘|‘<<mid+1<<‘,‘<<r<<endl;
        if (y<=mid) return query(x,y,l    ,mid,p*2  );
        if (x >mid) return query(x,y,mid+1,r  ,p*2+1);
            Range LRange,RRange,ans;
            LRange=query(x    ,mid,l    ,mid,p*2  );
            RRange=query(mid+1,y  ,mid+1,r  ,p*2+1);
            ans = LRange.sum()>RRange.sum() ? LRange : RRange;
            //cout<<"     max(Query)"<<ans.sum()<<endl;
            int MaxPos=queryMax(mid+1,y  ,mid+1,r  ,p*2+1),
                MinPos=queryMin(x    ,mid,l    ,mid,p*2  );
            //cout<<"          MaxPos:"<<MaxPos<<"  "<<"MinPos:"<<MinPos<<endl;
            if(A[MaxPos]-A[MinPos-1]>ans.sum()){
                ans.left  = MinPos;
                ans.right = MaxPos;
            }
            //cout<<"      max(max-min)"<<ans.sum()<<endl;
            return ans;
    }
    #undef MaxSegmentLength
};

SegmentTree Tree;

int main()
{
    int n,m,CaseNum=0;A[0]=0;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++) scanf("%lld",A+i);
        for(int i=2;i<=n;i++) A[i]+=A[i-1];

        Tree.build(1,n,Tree.root);
        printf("Case %d:\n",++CaseNum);

        for(int i=0;i<m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            Range ans = Tree.query(a,b,1,n,Tree.root);
            printf("%d %d\n",ans.left,ans.right);
        }
    }
    /*
    int N,delta;
    cin>>N;
    for(int i=1;i<=N;i++) cin>>A[i];
    //delta=A[1];
    //A[1]=A[0]=0;
    for(int i=2;i<=N;i++)
        A[i]+=A[i-1];//-delta;
    //for(int i=1;i<=N;i++)cout<<A[i]<<‘ ‘;
    //cout<<endl;
    Tree.build(1,N,Tree.root);
    int a,b;
    while(cin>>a>>b){
        Range ans = Tree.query(a,b,1,N,Tree.root);
        cout<<ans.left<<‘ ‘<<ans.right<<endl;
        //cout<<ans.left<<‘,‘<<ans.right<<endl<<endl;
    }
    */
    return 0;
}
//10
// 1  2  3  4  5  6  7  8  9  10
// 4  5  6  2  9  0 -1 13  9 -10
// 4  9 15 17 26 26 25 38 47  37
// 0  1  2 -2  5 -4 -5  9  5 -14

C - Plucking fruits

最小瓶颈树,跟kruskal类似

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn= 1010 ,maxm = maxn*maxn;

struct edge{int u,v,w;};
struct query{int u,v,d,ord;};
int f[maxn],n,m,r;
query q[maxm];
edge e[maxm];
int ord[maxm];
bool ans[maxm];

bool compe(edge  a,edge  b){return a.w>b.w ;}
bool compq(query a,query b){return a.d>b.d ;}

int Find(int x){ return f[x]==x ? x : f[x]=Find(f[x]);}
int Union(int x,int y){
    int fx = Find(x),fy = Find(y);
    if(fx!=fy){
        f[fx]=fy;
    }
    return 0;
} 

int main()
{
    int caseNuym = 1;
    while(scanf("%d%d%d",&n,&m,&r)!=EOF) {
        for(int i=1;i<=n;i++)f[i]=i;
        memset(ans,0,sizeof(ans));

        for(int i=0;i<m;i++)
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        for(int i=0;i<r;i++){
            scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].d);
            q[i].ord = i;
        }

        std::sort(e,e+m,compe);
        std::sort(q,q+r,compq);

        int head = 0;

        for(int i=0;i<r;i++){
            for(;(e[head].w>=q[i].d)&&(head<m);head++)
                Union(e[head].u,e[head].v);
            if(Find(q[i].u)==Find(q[i].v))
                ans[q[i].ord] = 1;
            else
                ans[q[i].ord] = 0;
        }
    printf("Case %d:\n",caseNuym );
    for (int i=0;i<r;++i)
    if (ans[i]) puts("yes"); else puts("no"); 

     ++caseNuym ;
    }

}

F - Remember the Word

动态规划f[i]表示单词的i前缀串划分为集合中字符的方案数

转移方程  f[i]=sigma(f[i-s[j].len]) s[j]是word[0..i]一个后缀

边界        f[0]=1

实际上写的时候考虑的是向后更新会比较方便。

f[i+s[j].len]+=f[i] (s[j]是word[i..end]一个前缀)

利用字典树找到一个状态的所有后继。

#include <cstdio>
#include <cstring>
#include <queue>

const long long maxnode    = 4010*100;
const long long SIGMA_SIZE = 26;
const long long maxlen     = 100;
const long long maxn       = 300010;
const long long MOD        = 20071027;

using namespace std;

char s[maxn];
int f[maxn];

struct Trie
{
    int ch[maxnode][SIGMA_SIZE];
    int val[maxnode];
    int size;
    Trie(){clear();}
    void clear(){
        size=1;
        memset(ch[0],0,sizeof(ch[0]));
        memset(val,0,sizeof(val));
    }
    int index(char t){return t-‘a‘;};
    int buildNewNode(int u){
        memset(ch[size],0,sizeof(ch[size]));
        val[size]=u;
        return size++;
    }
    void insert(char *s){
        int u = 0;
        for(;*s;s++){
            int c = index(*s);//忘记调用idx()WA了好几次
            if(!ch[u][c])
                ch[u][c]=buildNewNode(0);
            u=ch[u][c];
        }
        val[u]=1;//val[u]=v
    }
    void find(int i,char *s){
        int u=0,len=0;
        for(;*s;s++){
            int c = index(*s);//忘记调用idx()WA了好几次
            if(ch[u][c]){
                len++;
                u=ch[u][c];
                f[i+len]=(val[u]*f[i]+f[i+len])%MOD;
                //if(val[u]){find an end }
            }
            else
                break;
        }

    }
};

Trie trie;

int main()
{
    int CaseNum = 0;
    while(scanf("%s",s)!=EOF){
        int n,len=strlen(s);
        memset(f,0,sizeof(f));f[0]=1;
        trie.clear();

        scanf("%d",&n);
        for(int i=0;i<n;i++){
            char key[110];
            scanf("%s",key);
            trie.insert(key);
        }

        for(int i=1;i<=len;i++)
            trie.find(i-1,s+i-1);

        printf("Case %d: %d\n",++CaseNum,f[len]);

    }
    return 0;
}

I - Cake slicing

4D/1D的动态规划,就是枚举这一刀是横切还是竖切,记忆化搜索。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int maxn   = 20+10;
const int maxInt = 0x3f3f3f3f;

int A[maxn][maxn],f[maxn][maxn][maxn][maxn];

int sum(int x,int y,int a,int b)
    {return A[a][b]-A[x-1][b]-A[a][y-1]+A[x-1][y-1];}

int dfs(int x,int y,int a,int b){
    int S = sum(x,y,a,b),&ans=f[x][y][a][b];
    if(S==0)return maxInt;
    if(S==1)return 0;
    if(ans) return ans;
    ans=maxInt;
    for (int i = x; i < a; ++i)
    {
        ans = min(dfs(x,y,i,b)+dfs(i+1,y,a,b)+b-y+1,ans);
    }
    for (int i = x; i < a; ++i)
    {
        ans = min(dfs(x,y,a,i)+dfs(x,i+1,a,b)+a-x+1,ans);
    }
    return ans;
}

int main(int argc, char const *argv[])
{
    int n,m,k,CaseNum=0;
    while(cin>>n>>m>>k){
        memset(A,0,sizeof(A));
        memset(f,0,sizeof(f));

        for(int i=0;i<k;i++){
            int x,y;
            cin>>x>>y;
            A[x][y]=1;
        }
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= m; ++j)
            {
                A[i][j]+=A[i-1][j]+A[i][j-1]-A[i-1][j-1];
            }
        }
        int ans = dfs(1,1,n,n);
        cout<<"Case "<<++CaseNum<<": "<<ans<<endl;
    }
    return 0;
}

暑训day1解题报告

时间: 2024-10-07 13:04:57

暑训day1解题报告的相关文章

NOIp 2013 Day1 解题报告

NOIp 2013 Day1 解题报告 1.   转圈游戏 不难看出答案就是(x+m*10k) mod n 用快速幂算法,复杂度O(log2k) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,m,x,

常州培训 day1 解题报告

第一题: 题目大意:给出一个字符串,找出满足条件A的区间的个数.A:字符A,B,C的出现次数相同. 都出现0次也算,区间的长度可以是0(就是只有一个数).30% |S| ≤ 100 .70% |S| ≤ 1000 .100% 1 ≤ |S| ≤ 1000000 . 解题过程: 1.考场上想不出AC算法,但是70分是很好拿的,最先想到先求出A,B,C出现次数的前缀和,枚举区间的两个端点,O(1)时间判断,枚举O(n^2). 2.一看后面的题目都不是很好写,就先来优化一下这题,由于只有A,B,C是有

2016.8.25 NOIP2012 day1 解题报告

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

CH Round #54 - Streaming #5 (NOIP模拟赛Day1)解题报告

最近参加了很多CH上的比赛呢~Rating--了..题目各种跪烂.各种膜拜大神OTZZZ T1珠 描述 萌蛋有n颗珠子,每一颗珠子都写有一个数字.萌蛋把它们用线串成了环.我们称一个数字串是有趣的,当且仅当它的第1位是2,且除了第1位以外的每一位都是3.例如,2,233,2333333都是有趣的数字串.现在,你可以从这串珠子的任意一颗开始读,沿着顺时针或逆时针方向,到任意一颗珠子停止.这样,你就可以读出一个数字串来.萌蛋想知道,所有能读出的有趣的数字串当中,最长的是哪一个数字串.当然,你也可能读不

2017.7.15清北夏令营精英班Day1解题报告

成绩: 预计分数:20+10+40 实际分数:100+10+40. 一百三十多人的比赛全场rand7还水了个鼠标+键盘 unbelievable! 考试题目链接: https://www.luogu.org/team/show?teamid=1353 T1 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm&

NOIp 2011 Day1 解题报告

1.    铺地毯 送分题…… 枚举给定矩形,判定给定点是否在矩形内.求出标号最大的哪个矩形即可. 复杂度O(N) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,a[10010],b[10010],g

2014 UESTC 暑前集训队内赛(1) 解题报告

A.Planting Trees 排序+模拟 常识问题,将耗时排一个序,时间长的先种,每次判断更新最后一天的时间. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define Mod 1000000007 #define INT 2147483647 #define pi acos(-1.0)

2014 UESTC暑前集训数据结构专题解题报告

A.Islands 这种联通块的问题一看就知道是并查集的思想. 做法:从高水位到低水位依序进行操作,这样每次都有新的块浮出水面,可以在前面的基础上进行合并集合的操作.给每个位置分配一个数字,方便合并集合.同时将这些数字也排一个序,降低枚举的复杂度.合并集合时向四周查询浮出水面但是没有合并到同一集合的点进行合并. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath&

ecnu18级程设实训第一次机考简易解题报告

愉快(并不)地考完了,看到LDY大佬的题解,决定学习一个,也来写一份解题报告.当然,这会是一个比较简易的版本,可能有所缺漏,敬请谅解. 此处是LDY大佬题解的传送门: https://zhuanlan.zhihu.com/p/60305621 走过路过给个赞~ A. 恢复单词 单点时限: 2.0 sec 内存限制: 512 MB 学霸在背单词的时候发现单词的大小写混乱,而且可能参杂了0-9的数字和 %,+,&,#这四种特殊符号.请编写程序让单词恢复正常.要求处理后单词的首字母大写,且其余字母均为