contest 1000
Posted may-2nd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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*/
以上是关于contest 1000的主要内容,如果未能解决你的问题,请参考以下文章
Contest2195 - 2019-4-25 高一noip基础知识点 测试8 题解版
UCF Local Programming Contest 2017(2020-04-06)