期望得分:0+40+30=70

实际得分:0+10+10=20

题目修改:只能由0变1,只能用一次操作

大模拟

#include<cstdio>
#include<cstring>
using namespace std;
char s[];
int len,n;
int cnt[];
bool solve1()
{
if(len!=n) return false;
int num=;
for(int i=;i<len;i++)
if(s[i]=='') num+=i+;
if(num%(n+)==)
{
puts(s);
return true;
}
return false;
}
bool solve2()
{
if(len!=n) return false;
int num=;
for(int i=;i<len;i++)
if(s[i]=='') num+=i+;
for(int i=;i<len;i++)
if(s[i]=='')
{
num-=(i+);
if(num%(n+)==)
{
for(int j=;j<i;j++) putchar(s[j]);
putchar('');
for(int j=i+;j<len;j++) putchar(s[j]);
printf("\n");
return true;
}
num+=(i+);
}
return false;
}
bool solve3()
{
if(len<=n) return false;
int num=;
for(int i=;i<len;i++)
if(s[i]=='') num+=i+,cnt[i+]=cnt[i]+;
else cnt[i+]=cnt[i];
for(int i=;i<len;i++)
if(s[i]=='')
{
num-=(cnt[len]-cnt[i]);
if(num%(n+)==)
{
for(int j=;j<i;j++) putchar(s[j]);
for(int j=i+;j<len;j++) putchar(s[j]);
printf("\n");
return true;
}
num+=(cnt[len]-cnt[i]);
}
else
{
num-=(cnt[len]-cnt[i+]);
num-=(i+);
if(num%(n+)==)
{
for(int j=;j<i;j++) putchar(s[j]);
for(int j=i+;j<len;j++) putchar(s[j]);
printf("\n");
return true;
}
num+=(cnt[len]-cnt[i+]);
num+=(i+);
}
return false;
}
bool solve4()
{
if(len>=n) return false;
int num=;
for(int i=;i<len;i++)
if(s[i]=='') num+=(i+),cnt[i+]=cnt[i]+;
else cnt[i+]=cnt[i];
for(int i=;i<len;i++)
{
num+=cnt[len]-cnt[i];
if(num%(n+)==)
{
for(int j=;j<i;j++) putchar(s[j]);
putchar('');
for(int j=i;j<len;j++) putchar (s[j]);
printf("\n");
return true;
}
num+=i+;
if(num%(n+)==)
{
for(int j=;j<i;j++) putchar(s[j]);
putchar('');
for(int j=i;j<len;j++) putchar(s[j]);
printf("\n");
return true;
}
num-=(i+);
num-=(cnt[len]-cnt[i]);
}
if(num%(n+)==) { printf("%s",s); printf("0\n");return true; }
if((num+len+)%(n+)==) { printf("%s",s); printf("1\n"); return true; }
return false;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
while(scanf("%s",s)!=EOF)
{
len=strlen(s);
if(solve1()) continue;
if(solve2()) continue;
if(solve3()) continue;
if(solve4()) continue;
printf("-1\n");
}
}

题目中要求选的数 %m 互不相同

那么可以很自然的想到

先在<m的数里选k个 ,使他们的和 s%m=n%m,那么还剩下n-s

为了保证%m 不相同,所以 我们把剩下的n-s 分为 (n-s)/m 个 m,

给这k个数分 m

也就是说

如果要换掉x,只能用和x 模m属于同一剩余系 的数换,所以 只能加 m的整数倍

设f[i][j] 表示选了i个数,和为j,且选的i个数互不相同的方案数

设g[i][j]表示把i个m分给j个数的方案数

那么ans= Σ f[i][j] * g[(n-j)/m][i] * i !,  其中要求j%m=n%m

这里要乘i的阶乘,因为 1 2 和 2 1 算作不同的方案

如何求f[i][j] ?

很容易想到 f[i][j][k] 表示 选了i个数,和为j,选的数字中最大的为k的方案数

这样是m^4,TLE

其实可以压去第三维

两维的缺陷是 如果顺序枚举i,枚举j,再枚举现在选哪个数,不能保证选的数%m互不相同

因为对于同一个数k,可能f[i+1][j] 由 已经选了k的f[i][j-k]再选k转移而来

解决的方法是

先枚举当前选哪个数,再倒序枚举选了多少个数,再枚举这些数的和

这样就保证了对于同一个数k,不会让 i+1 由 i 转移

如何求g[i][j]?

把i个东西分给j个人,显然是组合数

C(i+j-1,j-1)

难道 还要逆元?

其实不用 ,这个C 化开为:

1*2* …… i+j-1

---------------------------------(这是分数线)

(1*2……j-1)*(1*2……*i)

= ((i+1)*(i+2)……*(i+j-1))/((j-1)!)

不要漏了 统计答案的时候还要乘上j! 所以分母消去只剩下个j

求 (i+1)*(i+2)……*(i+j-1) 的时候,i 本身可能是 long long ,不要忘了先取模,防止 乘爆

#include<cstdio>

#define M 101

using namespace std;

typedef long long LL;

const LL mod=;

int f[M][M*M/];

LL mul(LL a,LL b)
{
LL res=;
for(LL i=a;i<=b;i++) res*=i,res%=mod;
return res;
} int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
LL n; int m;
scanf("%I64d%d",&n,&m);
int mx=m*(m-)/;
f[][]=;
for(int k=;k<m;k++)
for(int i=m;i;i--)
for(int j=k;j<=mx;j++)
f[i][j]+=f[i-][j-k],f[i][j]%=mod;
int x=n%m; LL res,ans=,y;
for(int i=x;i<=mx && i<=n;i+=m)
{
y=(n-i)/m;
for(int j=;j<=m;j++)
if(f[j][i])
{
res=mul((y+)%mod,(y+j-)%mod);
res*=f[j][i]; res%=mod;
res*=j; res%=mod;
ans+=res,ans%=mod;
}
}
printf("%I64d",ans);
}

解决本题的突破点:

哪一年种哪些地可以随意定

dp[i] 表示 种过的最右边的地为i时的最大收益

将所有的种地区间按左端点从左到右排序

那么对于当前这个种地区间[l[i],r[i]]

它的上一个种地区间 [l[j],r[j]],

l[j]一定<=l[i]

r[j]可能有三种情况

① r[j] < l[i] 此时第i块地 有全部的垦荒代价

② r[j]∈[l[i],r[i]) 此时第i块地 有 右边部分的垦荒代价

③ r[j]>=r[i] 此时第i块地 没有垦荒代价

令sum[i]表示垦荒代价的前缀和,val[i]表示第i次垦荒的收益

那么对应的状态转移方程:

① dp[r[i]]=max(dp[r[j]]+val[i]-(sum[r[i]]-sum[l[i]-1]))

② dp[r[i]]]=max(dp[r[j]]+val[i]-(sum[r[i]]-sum[r[j]]))

③ dp[r[j]]+=val[i]

朴素的dp为O(n^2)

可用线段树优化至nlogn

在 r[j]==r[i] 时,有很多细节

线段树的没调出来

30分 n^2代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> #define N 200001 using namespace std; typedef long long LL; LL sum[N],dp[N];
int vis[N]; struct node
{
int l,r,p;
}e[N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} bool cmp(node p,node q)
{
if(p.l!=q.l) return p.l<q.l;
return p.r<q.r;
} int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
int n,m,x;
read(n); read(m);
for(int i=;i<=n;++i) read(x),sum[i]=sum[i-]+x;
for(int i=;i<=m;++i) read(e[i].l),read(e[i].r),read(e[i].p);
sort(e+,e+m+,cmp);
memset(dp,-,sizeof(dp));
for(int i=;i<=m;i++)
{
LL tmp=-1e18; bool ok=false;
dp[e[i].r]=max(dp[e[i].r],e[i].p-(sum[e[i].r]-sum[e[i].l-]));
tmp=dp[e[i].r];
for(int j=i-;j;j--)
if(e[j].r<e[i].l) dp[e[i].r]=max(dp[e[i].r],dp[e[j].r]+e[i].p-(sum[e[i].r]-sum[e[i].l-]));
else if(e[j].r<e[i].r) dp[e[i].r]=max(dp[e[i].r],dp[e[j].r]+e[i].p-(sum[e[i].r]-sum[e[j].r]));
else if(vis[e[j].r]!=i) // 一个e[i].p只能累计一次到一个e[j].r 里
{
if(e[j].r==e[i].r) ok=true;//e[i].r==e[j].r 时,r 可能被 前两种情况修改过,但累计的话只能是用没有修改过的
else dp[e[j].r]+=e[i].p,vis[e[j].r]=i;
}
if(ok) dp[e[i].r]=max(dp[e[i].r],tmp+e[i].p);
}
LL ans=;
for(int i=;i<=n;i++) ans=max(ans,dp[i]);
printf("%I64d",ans);
}

std

#include <cstdio>
#include <cctype>
#include <memory.h>
#include <algorithm> using namespace std; typedef long long qw; #ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif int nextInt() {
int s = , d;
bool nag = ;
do {
d = getchar();
if (d == '-')
nag = ;
} while (!isdigit(d));
do
s = s * + d - , d = getchar();
while (isdigit(d));
return nag ? -s : s;
} struct seg {
int l, r;
qw v, z;
seg *ls, *rs;
};
struct obj {
int l, r, v;
}; inline bool cmpObj(const obj& a, const obj& b) {
return (a. l < b. l) || (a. l == b. l && a. r < b. r);
} const int maxn = ;
const qw inf = 0x3f3f3f3f3f3f3f3fLL; int n, m;
obj q[maxn];
qw s[maxn], ans;
seg *rtf, *rtc, *sp; #define mid(p) ((p->l+p->r)>>1) seg *sgtBuild(int l, int r) {
seg *p = sp ++;
p-> v = - inf;
p-> z = ;
p-> l = l;
p-> r = r;
if (l + < r) {
p-> ls = sgtBuild(l, mid(p));
p-> rs = sgtBuild(mid(p), r);
}
return p;
} void sgtChg(seg* p, int p0, qw v0) {
if (p-> l + == p-> r)
p-> v = max(p-> v, v0);
else {
if (p0 < mid(p))
sgtChg(p-> ls, p0, v0 - p-> z);
else
sgtChg(p-> rs, p0, v0 - p-> z);
p-> v = max(p-> ls-> v, p-> rs-> v) + p-> z;
}
} qw sgtQry(seg* p, int l, int r) {
if (l >= r)
return -inf;
else if (p-> l == l && p-> r == r)
return p-> v;
else if (r <= mid(p))
return sgtQry(p-> ls, l, r) + p-> z;
else if (l >= mid(p))
return sgtQry(p-> rs, l, r) + p-> z;
else
return max(sgtQry(p-> ls, l, mid(p)), sgtQry(p-> rs, mid(p), r)) + p-> z;
} void sgtLazy(seg* p, int l, qw z0) {
if (p-> v == -inf)
return;
else if (p-> l == l)
p-> v += z0, p-> z += z0;
else {
if (l < mid(p)) {
sgtLazy(p-> ls, l, z0);
sgtLazy(p-> rs, mid(p), z0);
}
else
sgtLazy(p-> rs, l, z0);
p-> v = max(p-> ls-> v, p-> rs-> v) + p-> z;
}
} int main() {
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
sp = new seg[maxn * ];
n = nextInt();
m = nextInt();
rtf = sgtBuild(, n + );
rtc = sgtBuild(, n + );
s[] = ;
for (int i = ; i <= n; i ++)
s[i] = s[i - ] + nextInt();
for (int i = ; i < m; i ++) {
q[i]. l = nextInt();
q[i]. r = nextInt();
q[i]. v = nextInt();
}
sort(q, q + m, cmpObj);
ans = ;
for (int i = ; i < m; i ++) {
qw res0 = max(sgtQry(rtf, , q[i]. l), 0LL) - s[q[i]. r] + s[q[i]. l - ];
qw res1 = sgtQry(rtc, q[i]. l, q[i]. r + ) - s[q[i]. r];
qw res = max(max(res0, res1), sgtQry(rtf, q[i]. r, n + )) + q[i]. v;
sgtLazy(rtf, q[i]. r, q[i]. v);
sgtLazy(rtc, q[i]. r, q[i]. v);
sgtChg(rtf, q[i]. r, res);
sgtChg(rtc, q[i]. r, res + s[q[i]. r]);
ans = max(ans, res);
printf("%I64d %I64d\n",res,ans);
}
printf(lld "\n", ans);
}

没跳出来&&不想调的线段树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> #define N 200001 using namespace std; typedef long long LL; LL sum[N]; LL mx1[N<<],mx2[N<<],f[N<<]; LL t1,t2; struct node
{
int l,r,p;
}e[N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} bool cmp(node p,node q)
{
if(p.l!=q.l) return p.l<q.l;
return p.r<q.r;
} void change(int k,int l,int r,int pos,LL w,int ty)
{
if(l==r)
{
if(ty==) mx1[k]=max(mx1[k],w);
else mx2[k]=max(mx2[k],w);
return;
}
int mid=l+r>>;
if(pos<=mid) change(k<<,l,mid,pos,w,ty);
else change(k<<|,mid+,r,pos,w,ty);
mx1[k]=max(mx1[k<<],mx1[k<<|])+f[k];
mx2[k]=max(mx2[k<<],mx2[k<<|])+f[k];
} int query(int k,int l,int r,int opl,int opr,int ty)
{
if(l>=opl && r<=opr)
{
if(ty==) return max(t1,mx1[k]);
return max(t2,mx2[k])a;
}
int mid=l+r>>;
if(opr<=mid) return query(k<<,l,mid,opl,opr,ty)+f[k];
if(opr>mid) return query(k<<|,mid+,r,opl,opr,ty)+f[k];
return max(query(k<<,l,mid,opl,opr,ty),query(k<<|,mid+,r,opl,opr,ty))+f[k];
} void add(int k,int l,int r,int pos,int w)
{
if(l==pos)
{
f[k]+=w;
mx1[k]+=w;
mx2[k]+=w;
return;
}
int mid=l+r>>;
if(pos<=mid) add(k<<,l,mid,pos,w),add(k<<|,mid+,r,mid+,w);
else add(k<<|,mid+,r,pos,w);
mx1[k]=max(mx1[k<<],mx1[k<<|])+f[k];
mx2[k]=max(mx2[k<<],mx2[k<<|])+f[k];
} int main()
{
// freopen("8.in","r",stdin);
// freopen("c.out","w",stdout);
int n,m,x; LL ans=;
read(n); read(m);
for(int i=;i<=n;++i) read(x),sum[i]=sum[i-]+x;
for(int i=;i<=m;++i)
read(e[i].l),read(e[i].r),read(e[i].p);
sort(e+,e+m+,cmp);
memset(mx2,-,sizeof(mx2));
memset(mx1,-,sizeof(mx1));
LL now;
for(int i=;i<=m;i++)
{
t1=query(,,n,e[i].l,e[i].r,);//2
t2=query(,,n,e[i].r,n,);
now=t1+e[i].p-sum[e[i].r];//
now=max(now,t2+e[i].p);
t2=query(,,n,,e[i].l,);
now=max(now,t2+e[i].p-sum[e[i].r]+sum[e[i].l-]);//
ans=max(ans,now);
add(,,n,e[i].r,e[i].p);
change(,,n,e[i].r,now+sum[e[i].r],);
change(,,n,e[i].r,now,); printf("%I64d %I64d\n",now,ans);
}
printf("%I64d",ans);
}

2017北京国庆刷题Day4 morning的更多相关文章

  1. 2017北京国庆刷题Day4 afternoon

    期望得分:100+100+0=200 实际得分:5+0+0=5 每加入一个数,x的因数位置++ 注意:根号x枚举时,如果x是完全平方数,根号x会重复累计2次,要减去 考场上没减,5分 /(ㄒoㄒ)/~ ...

  2. 2017北京国庆刷题Day1 afternoon

    期望得分:100+100+100=300 实际得分:100+100+100=300 T1 一道图论好题(graph) Time Limit:1000ms   Memory Limit:128MB 题目 ...

  3. 2017北京国庆刷题Day7 morning

    期望得分:100+0+100=200 实际得分:100+20+0=120 离散化搞搞 #include<cstdio> #include<iostream> #include& ...

  4. 2017北京国庆刷题Day5 afternoon

    期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)… ...

  5. 2017北京国庆刷题Day3 morning

    期望得分:100+60+0=160 实际得分:100+30+0=130 考场上用的哈希 #include<cstdio> #include<cstring> #include& ...

  6. 2017北京国庆刷题Day2 afternoon

    期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一 ...

  7. 2017北京国庆刷题Day2 morning

    期望得分:100+100+40=240 实际得分:100+40+0=140 T1 一道图论神题(god) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK ...

  8. 2017北京国庆刷题Day5 morning

    期望得分:0+60+60=120 实际得分:0+30+60=90 令g=gcd(X11,X12,X13……) 则行列式可能为D的充要条件为g|D 1.g|D为必要条件: 由定义来算行列式的时候,每一项 ...

  9. 2017北京国庆刷题Day6 afternoon

    期望得分:100+100+40=240 实际得分:100+0+40=140 二进制拆分.二进制前缀和 #include<cstdio> #include<iostream> u ...

随机推荐

  1. centos svn 服务器间的数据迁移

    svnadmin dump erp > ~/erp.svn   当前目录下的erp 导出到根目录下名为erp.svn tar -zcvf backupSvn.tar.gz backupSvn   ...

  2. 回滚 - 每天5分钟玩转 Docker 容器技术(141)

    kubectl apply 每次更新应用时 Kubernetes 都会记录下当前的配置,保存为一个 revision(版次),这样就可以回滚到某个特定 revision. 默认配置下,Kubernet ...

  3. c#抽取pdf文档标题——前言

    由于工作的需要,研究c#抽取pdf文档标题有3个月了.这项工作是一项"伟大而艰巨"的任务.应该是我目前研究工作中最长的一次.我觉得在长时间忙碌后,应该找些时间,把自己的心路历程归纳 ...

  4. Django用户登录与注册系统

    一.创建项目 1.1.创建项目和app python manage.py startproject mysite_login python manage.py startapp login 1.2.设 ...

  5. epoll 实现回射服务器

    epoll是I/O复用模型中相对epoll和select更高效的实现对套接字管理的函数. epoll有两种模式 LT 和 ET 二者的差异在于 level-trigger 模式下只要某个 socket ...

  6. Php显示中文时乱码

    <?php echo "你们好哈"; ?> 显示乱码,解决办法 <?php header("content-type:text/html; charse ...

  7. redis五种基本类型CRUD操作

    1.String 增:set key1 value1 改:set key1 new-value.自增 incr key1.按照特定值递增:increby key1 inrevalue 删:del ke ...

  8. Linux设备驱动框架设计

    引子 Linux操作系统的一大优势就是支持数以万计的芯片设备,大大小小的芯片厂商工程师都在积极地向Linux kernel提交设备驱动代码.能让这个目标得以实现,这背后隐藏着一个看不见的技术优势:Li ...

  9. 【windows】 配置一个本地的tomcat服务器

    配置tomcat 公司的许多业务都是用java+tomcat模式的,做本地测试的时候经常要搭建一个自己的tomcat服务器.整个操作不难,但是记录一下,万一以后遇到什么问题也可以放这里. ■ 安装ja ...

  10. 总结linux路由技术

    Linux系统的route命令用于显示和操作IP路由表,要实现两个不同的网段之间的通信,需要一台连接两个网络的路由器,或者同时连接位于两个网络的网关来实现. 在Linux系统中,设置路由通常是为了解决 ...