Day2下午

虽然成绩不太好,但有点进入状态了。期望200 实际160,忘记加判断了。

T1

洗澡
【问题描述】
你是能看到第一题的friends 呢。
——hja
洗澡的地方,有一段括号序列,将一个括号修改一次需要1的代价(将左括
号变成右括号或者相反),求最小代价使得括号序列合法。
【输入格式】
一行一个括号序列。
【输出格式】
一行一个整数代表答案。
【样例输入】
())(
【样例输出】
2
【数据范围与规定】
对于50%的数据,括号序列长度不超过100。
对于100%的数据,括号序列长度不超过105且一定为偶数,只包含小括
号。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
using namespace std;
char s[100009];
int len;
int ans,sum;
int main()
{
    freopen("shower.in","r",stdin);
    freopen("shower.out","w",stdout);
    cin>>(s+1);
    len=strlen(s+1);
    for(int i=1;i<=len;i++)
    {
        if(s[i]=='(')    sum++;
        else sum--;
        if(sum<0)    ans++,sum+=2;        
    }
    if(sum)    ans+=sum/2;
    cout<<ans;
    return 0;
}
第一遍AC

 直接模拟。

T2

日记
【问题描述】
你是能看到第二题的 friends呢。
—— laekov
日记之中,写满了质数两个间如果没有其他那么则称为相 邻的质数。给定 𝑁,𝑘,询问不超过 𝑁的数中能够表示成连续 𝑘个质数之和的最大 的数是多少。
【输入格式】
第一行个整数 𝑇代表数据组。
对于每组数据,一行 行两个整数 𝑁,𝑘。
【输出格式】
对于每组数据,一行个整代表答案。如果不存在则输出 −1。
【样例输入】
3
20 2
20 3
20 4
【样例输出】
18
15
17
【数据范围与规定】
对于 20%的数据 ,1≤𝑁≤100。
对于 40%的数据 ,𝑇=1。
对于 另外 20%的数据 ,所有的 询问𝑁相等 。
对于 100%的数据 ,1≤𝑇<2000,1≤𝑁≤106。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
using namespace std;
const int N=1000000+4;
int prime[N],cnt;
bool is[N];
int T;
void first()
{
    cnt=0;
    for(int i=2;i<=N;i++)
    {
        if(!is[i])    prime[++cnt]=i;
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>N)    break;
            is[i*prime[j]]=1;
            if(i%prime[j]==0)    break;
        }
    }
    return ;
}
int work(int mid,int len)
{
    int sum=0;
    for(int i=mid;i<=mid+len-1;i++)
    sum+=prime[i];
    return sum;
}
int main()
{
    freopen("diary.in","r",stdin);
    freopen("diary.out","w",stdout);
    first();
    scanf("%d",&T);
    for(int i=1,n,k;i<=T;i++)
    {
        scanf("%d%d",&n,&k);
        int j=1,sum=0,L,R,mid;
        if(n<=100)
        {
            j=1,sum=0;
            for(j=1;j<=k;j++)    sum+=prime[j];j--;
            if(n<sum)
            {
                printf("-1\n");
                continue;
            }
            while(sum+prime[j+1]-prime[j-k+1]<=n)
                sum=sum+prime[j+1]-prime[j-k+1],j++;
            printf("%d\n",sum);
            continue;
        }
        L=1,R=cnt-k+1;
        while(L<=R)
        {
            mid=(L+R)>>1;
            if(work(mid,k)<=n)    L=mid+1;
            else R=mid-1;
        }
        for(j=min(cnt,L);j>=R;j--)
        if((sum=work(j,k))<=n)
        {
            printf("%d\n",sum);
            break;
        }
    }    
    return 0;
}
第一遍60

 可恶啊,就差求个前缀和。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<ctime>
using namespace std;
const int N=1000000+4;
int prime[N],cnt;
int f[N];
bool is[N];
int T;
void first()
{
    cnt=0;
    for(int i=2;i<=N;i++)
    {
        if(!is[i])    prime[++cnt]=i;
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>N)    break;
            is[i*prime[j]]=1;
            if(i%prime[j]==0)    break;
        }
    }
    for(int i=1;i<=cnt;i++)
        f[i]=f[i-1]+prime[i];
    return ;
}
int work(int mid,int len)
{    return f[mid+len-1]-f[mid-1];}
int main()
{
    freopen("diary.in","r",stdin);
    freopen("diary.out","w",stdout);
    first();
    scanf("%d",&T);
    for(int i=1,n,k;i<=T;i++)
    {
        scanf("%d%d",&n,&k);
        int j=1,sum=0,L,R,mid;
        if(n<=100)
        {
            j=1,sum=0;
            j=k;
            sum=f[j];
            if(n<sum)
            {
                printf("-1\n");
                continue;
            }
            while(sum+prime[j+1]-prime[j-k+1]<=n)
                sum=sum+prime[j+1]-prime[j-k+1],j++;
            printf("%d\n",sum);
            continue;
        }
        sum=f[k];
        if(n<sum)
        {
            printf("-1\n");
            continue;
        }
        L=1,R=cnt-k+1;
        while(L<=R)
        {
            mid=(L+R)>>1;
            if(work(mid,k)<=n)    L=mid+1;
            else R=mid-1;
        }
        for(j=min(cnt,L);j>=R;j--)
        if((sum=work(j,k))<=n)
        {
            printf("%d\n",sum);
            break;
        }
    }    
    return 0;
}
未评测

 

思路:先筛素数,可以先求个前缀和!然后二分起点。

T3

洗衣
【问题描述】
你是能看到第三题的 friends呢。
—— aoao
洗完衣服,就要晒在树上 洗完衣服,就要晒在树上 。但是这个世界并没有树,我们需要重新开始造。 但是这个世界并没有树,我们需要重新开始造。 我们一开始拥有 𝑇0,是一棵只有个点的树,我们要用它造出更多。
生成第 𝑖棵树我们需要五个参数 𝑎𝑖,𝑏𝑖,𝑐𝑖,𝑑𝑖,𝑙𝑖(𝑎𝑖,𝑏𝑖<𝑖)。我们生成第 。我们生成第 𝑖棵树是 将第 𝑎𝑖棵树的 𝑐𝑖号点和第 𝑏𝑖棵树的 𝑑𝑖号点用一条长度为 号点用一条长度为 号点用一条长度为 号点用一条长度为 号点用一条长度为 号点用一条长度为 号点用一条长度为 号点用一条长度为 𝑙𝑖的边连接起来形成新 的边连接起来形成新 的树 (不会改变原来两棵树 不会改变原来两棵树 不会改变原来两棵树 不会改变原来两棵树 )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: )。下面我们需要对新树中的点重编号: 对于原来在 第𝑎𝑖棵树中的点 ,我们不会改变他的编号 ;对于原来在第 𝑏𝑖棵树中的点 ,我们 会将他们的编号加上第 𝑎𝑖棵树的点个数作为新编号 。
定义 𝐹(𝑇𝑖)=ΣΣ𝑑(𝑣𝑖,𝑣𝑗)𝑛−1𝑗=𝑖+1𝑛−1𝑖=0
其中 ,𝑛为树 𝑇𝑖的大小 ,𝑣𝑖,𝑣𝑗是𝑇𝑖中的 点, 𝑑(𝑣𝑖,𝑣𝑗)代表这两个点的距离。现 代表这两个点的距离。现 在希望你求出 ∀1≤𝑖≤𝑚,𝐹(𝑇𝑖)是多少 。
【输入格式】
第一行 一个整数 𝑚,代表要造多少棵树 。
接下来 𝑚行 ,每5个数 𝑎𝑖,𝑏𝑖,𝑐𝑖,𝑑𝑖,𝑙𝑖。
【输出格式】
𝑚行每一个整数代表 𝐹(𝑇𝑖)对109+7取模之后的值 。
【样例输入】
3
0 2
1 0 4
2 1 0 3
【样例输出】
2
28
216

【数据规模与约定】
对于 30%的数据, 1≤m≤10。
对于 60%的数据 ,每棵树的点数个不超过 105。
对于 100%的数据 ,1≤m≤60。

 0

思路:30分建树后,暴力算。

  60分线性做法,树形dp。?不会啊

  三重dp。

  两棵树并起来,只需算再算端点在两边的。 

  每个点  乘 右边树上总路程的和

  为避免没必要的运算,开map,记忆化搜索,求需要的。

  他竟然还想把longlong爆掉!

posted @ 2017-10-29 16:05  浪矢-CL  阅读(495)  评论(3编辑  收藏  举报