0%

cf3

近日补题

最近量很少啊,都不敢打比赛了

1033C|1600|DP

这题的有序性(无后效性)体现在a只能不断增加,当前阶段的a的值能表出之前所有a的范围。排序后从后向前dp即可,注意排序后index乱了,我们每步操作需要判断随机index的必胜必败(dp结果是每个数是必胜必败,根据基本博弈知识即可),不能顺序遍历,所以用map存即可,注意不存在(未出现和必败要区分,因为未出现体现的是a的大小,而不是index)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
struct ui{int fir;int sec;bool operator<(const ui b)const{return this->fir<b.fir;}};
const int maxn=1e5+10;
ui in[maxn];
int dp[maxn];
int tmp;
int main()
{
std::ios::sync_with_stdio(false);std::cin.tie(0);
int n;cin>>n;
for(int i=1;i<=n;++i)dp[i]=0;
map<int ,int> ma;
for(int i=1;i<=n;++i){
cin>>tmp;
in[i]={tmp,i};
}
sort(in+1,in+n+1);
for(int i=n;i>0;--i){
int tmp=1;
int tag=0;
while(1){
if(in[i].sec+tmp*in[i].fir>n)break;
else{
if(ma[in[i].sec+tmp*in[i].fir]==2){
tag=1;
}
}
tmp++;
}
tmp=1;
while(1){
if(in[i].sec-tmp*in[i].fir<1)break;
else{
if(ma[in[i].sec-tmp*in[i].fir]==2){
tag=1;
}
}
tmp++;
}
if(tag)dp[in[i].sec]=1;
else dp[in[i].sec]=2;
ma[in[i].sec]=dp[in[i].sec];
}
for(int i=1;i<=n;++i){
if(dp[i]==1)cout<<"A";
else cout<<"B";
}cout<<endl;
}

888D|1600|数学

k只有4,找规律,比如k为4时,就是恰好4个加恰3加恰2,求出恰好的值即可,这个恰好,可以用容斥(但我没推出来),也可以直接看每种个数有几个排列。
注意组合数很大(爆int)且不模时,不能用费马小定理(需要找一个足够大质数)。
k为3和4时需要找出恰3、4的个数(可以直接枚举),能造成全不一样的只有两种,轮换和两两交换,其中3只有轮换,3-1=2;4也有轮换,不过是6个(可以用树型遍历出来),交换为4-1=3,共9个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const ll N=2500;
ll C[N][N],n,a,b;
void init(){
for(ll i=0;i<N;++i){
for(ll j=0;j<=i;j++){
if(j==0)
C[i][j]=1;
else{
C[i][j]=(C[i-1][j-1]+C[i-1][j]);
}
}
}
}
ll A[2000];
int main()
{
std::ios::sync_with_stdio(false);std::cin.tie(0);
ll n,k;cin>>n>>k;
init();
A[1]=1;
for(ll i=2;i<1005;++i){
A[i]=A[i-1]*i;
}
if(k==1){
cout<<1<<endl;
return 0;
}else if(k==2){
cout<<C[n][2]+1<<endl;
}else if(k==3){
cout<<C[n][3]*2+C[n][2]+1<<endl;
}else{
cout<<C[n][4]*9+C[n][3]*2+C[n][2]+1<<endl;
}
}

1032C|1700|dp

他不断向后走,且只用管最后一位手指,满足无后效性;步步可行即可行,满足最优化原理。
dp需要2个变量,第i位,是从前一位的第几个手指而来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const int maxn = 2e5+10;
int in[maxn];
int dp[maxn][6];
int main(){
int n;cin>>n;
for(int i=1;i<=n;++i){
cin>>in[i];
}
for(int i=1;i<=5;++i){
dp[1][i]=1;
}
for(int i=2;i<=n;++i){
if(in[i-1]==in[i]){
for(int j=1;j<=5;++j){
for(int k=1;k<=5;++k){
if(j!=k&&dp[i-1][j]!=0){
dp[i][k]=j;
}
}
}
}else if(in[i-1]<in[i]){
for(int j=1;j<=5;++j){
if(dp[i-1][j]!=0){
for(int k=j+1;k<=5;++k){
dp[i][k]=j;
}
}
}
}else{
for(int j=1;j<=5;++j){
if(dp[i-1][j]!=0){
for(int k=1;k<j;++k){
dp[i][k]=j;
}
}
}
}
}
int tag=0,pos=-1;
for(int i=1;i<=5;++i){
if(dp[n][i]){
tag=1;pos=i;
break;
}
}
if(tag==0){
cout<<-1<<endl;
}else{
stack<int> stk;
stk.push(pos);
for(int i=n;i>1;--i){
stk.push(dp[i][pos]);
pos=dp[i][pos];
}
while(stk.size()){
cout<<stk.top()<<' ';
stk.pop();
}
cout<<endl;
}
}

835c|1600|区间dp

简单的区间dp,每个区间存初始亮度为0…c的个数,最后求出区间内各自个数再统计即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const int maxn=1005;
int dp[105][105][11];
int main()
{
std::ios::sync_with_stdio(false);std::cin.tie(0);
int n,q,c;cin>>n>>q>>c;
int x,y,s;
for(int i=1;i<=n;++i){
cin>>x>>y>>s;
dp[x][y][s]++;
}
for(int i=1;i<=100;++i){
for(int j=1;j<=100;++j){
for(int k=0;k<=c;++k){
dp[i][j][k]+=dp[i-1][j][k];
dp[i][j][k]+=dp[i][j-1][k];
dp[i][j][k]-=dp[i-1][j-1][k];
}
}
}
int t,x1,y1,x2,y2;
while(q--){
cin>>t>>x1>>y1>>x2>>y2;
int tmp[11];
for(int i=0;i<=c;++i){
tmp[i]=dp[x2][y2][i]-dp[x1-1][y2][i]-dp[x2][y1-1][i]+dp[x1-1][y1-1][i];
}
int ans=0;
for(int i=0;i<=c;++i){
ans+=tmp[i]*((t+i)%(c+1));
}
cout<<ans<<endl;
}
}

1061c|1700|dp

维护当前数是第几个,即可满足无后效性。
看复杂度,1e5*sqrt(1e6),再看time limit:3s,刚好。
cnt中存能排在i位的数现在出现了几个。一个数排如果可以排第i个,则答案增加cnt[i-1];
实现是:遍历过程实时加答案,计算答案时不能考虑自己,所以计算完答案后再遍历一次更新cnt。
更新cnt时,同样注意不能影响自己 ,所以要从大因子开始,为了变为sqrt的复杂度,先从1到sqrt,取其和a[i]除的结果更新;然后从sqrt到1,更新。
注意,此类优化方法,虽然把复杂读降为sqrt,产生的因子还是n的,不能开sqrt的cnt!!!!(re8发)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const int maxn=1e5+100;
ll a[maxn];
ll cnt[1000000];
int main()
{
std::ios::sync_with_stdio(false);std::cin.tie(0);
int n;cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
}
ll ans=0;
cnt[0]=1;
for(ll i=1;i<=n;++i){
ll tmp=sqrt(a[i]);
for(ll j=1;j*j<=a[i];++j){
if(a[i]%j==0){
ans+=cnt[j-1]+cnt[(a[i]/j)-1];
if(j*j==a[i])ans-=cnt[j-1];
ans%=mod;
}
}


for(ll j=1;j*j<=a[i];++j){
if(a[i]%j==0){
if(j*j!=a[i])cnt[a[i]/j]+=cnt[(a[i]/j)-1];
cnt[a[i]/j]%=mod;
}
}
for(ll j=tmp;j>=1;--j){
if(a[i]%j==0){
cnt[j]+=cnt[j-1];
cnt[j]%=mod;
}
}

}
cout<<ans<<endl;
}