contest 1000

A:贪心。因为一次可以改多个字符,所以一次就能将一个字符串匹配为一个模板串。搞个 map 记一下模板串的个数,接着字符串能直接匹配就直接匹配,否则花费一次修改。

#include<bits/stdc++.h>
using namespace std;
#define For(i,x,y)for(i=x;i<=y;i++)
map<string,int>mp;
string str;
int main()
{
    int s,n,i;
    cin>>n;
    s=n;
    For(i,1,n)
    {
        cin>>str;
        if(!mp.count(str))mp[str]=1;
        else mp[str]++;
    }
    For(i,1,n)
    {
        cin>>str;
        if(mp.count(str)&&mp[str])s--,mp[str]--;
    }
    cout<<s;
    return 0;
}
/*3
XS
XX
M
XS
XS
M*/

B:很明显改变某盏灯的状态它后面的灯的状态也都会改变,统计开灯时间和关灯时间的后缀和,枚举在哪两盏灯之间改变这个状态。这样一定只有两种选择,要么在某个时间结点后一时立刻改变,要么在某个时间结点前一时才改变,其中间的时刻均可以移动到两点从而变得更优。

#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define Max(x,y)(x>y?x:y)
#define For(i,x,y)for(i=x;i<=y;i++)
#define Down(i,x,y)for(i=x;i>=y;i--)
int tim[N][2],a[N];
int main()
{
    int n,m,i,mx;
    scanf("%d%d",&n,&m);
    For(i,1,n)scanf("%d",&a[i]);
    a[n+1]=m;
    Down(i,n,0)
    {
        tim[i][1]=tim[i+1][1];
        //关灯时间 
        tim[i][0]=tim[i+1][0];
        //开灯时间 
        tim[i][i&1]+=a[i+1]-a[i];
    }
    /*printf("%d",tim[0][0]);*/
    mx=/*0*/tim[0][0];
    Down(i,n,0)
    {
        if(a[i+1]>a[i]+1)mx=Max(mx,tim[i][1]+tim[0][0]-tim[i][0]+(i&1?-1:1));
        if(a[i+1]>a[i]+1)mx=Max(mx,tim[i+1][1]+tim[0][0]-tim[i+1][0]+(i&1?1:-1));
    }
    printf("%d",mx);
    return 0;
}

C:如果数据范围小可以直接离线差分,考虑我们差分的过程,实际上有很多位置都是没有用的,改变的位置最多只有 \(2n\) 个,相邻两个位置之间的值都不变。所以把端点拉出来排个序就可以模拟差分了,每次统计答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 400005
#define For(i,x,y)for(i=x;i<=y;i++)
struct line
{
    ll w;
    int v;
}p[N];
ll ans[N];
ll read()
{
    ll A;
    bool K;
    char C;
    C=A=K=0;
    while(C<'0'||C>'9')K|=C=='-',C=getchar();
    while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
    return(K?-A:A);
}
void write(ll X)
{
    if(X<0)putchar('-'),X=-X;
    if(X>9)write(X/10);
    putchar(X%10|48);
}
inline bool cmp(line _,line __)
{
    return _.w<__.w;
}
int main()
{
    ll l,r;
    int n,i,cnt,now;
    n=read();
    now=cnt=0;
    For(i,1,n)
    {
        l=read(),r=read();
        p[++cnt].w=l;
        p[cnt].v=1;
        p[++cnt].w=r+1;
        p[cnt].v=-1;
    }
    sort(p+1,p+cnt+1,cmp);
    now=p[1].v;
    For(i,2,cnt)ans[now]+=p[i].w-p[i-1].w,now+=p[i].v;
    For(i,1,n)write(ans[i]),putchar(' ');
    return 0;
}

D:首先将数组翻转,便于转移。设 \(f_i\) 表示以第 \(i\) 个数结尾的序列有多少个好子序列,枚举一个 \(j\),将 \(j\) 结尾的好子序列拼上一个好数组,根据乘法原理相乘即可。好数组的个数用组合数算,在 \(i-j-1\) 个数里选取 \(a_i\) 个(第 \(i\) 个数已经选取)。记得最终累加 \(f\) 数组。

#include<bits/stdc++.h>
using namespace std;
#define N 1005
#define Mod 998244353
#define For(i,x,y)for(i=x;i<=y;i++)
#define Down(i,x,y)for(i=x;i>=y;i--)
int fac[N],inv[N],a[N],f[N];
namespace BASICMATH
{
    inline void inc(int&x,int y)
    {
        x=(x+y)%Mod;
    }
}
using namespace BASICMATH;
int ksm(int x,int y)
{
    if(!y)return 1;
    return 1LL*ksm(1LL*x*x%Mod,y>>1)*(y&1?x:1)%Mod;
}
int C(int x,int y)
{
    if(y>x)return 0;
    return 1LL*fac[x]*inv[y]%Mod*inv[x-y]%Mod;
}
int main()
{
    int n,i,j,tot=0;
    cin>>n;
    fac[1]=1;
    For(i,2,n)fac[i]=1LL*fac[i-1]*i%Mod;
    inv[n]=ksm(fac[n],Mod-2);
    Down(i,n-1,0)inv[i]=1LL*inv[i+1]*(i+1)%Mod;
    For(i,1,n)cin>>a[n-i+1];
    f[0]=1;
    //基数 
    For(i,1,n)
    {
        if(a[i]>0)
        For(j,0,i-a[i]-1)inc(f[i],1LL*f[j]*C(i-j-1,a[i])%Mod);
        //强制选取i 
        inc(tot,f[i]);
    }
    cout<<tot;
    return 0;
}
/*4
2 2 1 1*/

猜你喜欢

转载自www.cnblogs.com/May-2nd/p/12505762.html