119 条题解
-
21464942666 LV 8 @ 2016-11-13 21:16:41
本题可以
###***贪心***。
按照贪心的指导思想,我们要求写每篇论文的时间最短。
1.大概做法:我们可以通过YY之后求出 写每篇论文的时间,然后将他们进行**排序**,然后取**前n个**相加即可。
2.求每篇论文的时间的方法如下:
i. 比如说对于 第1个课题:
第1篇:a1*(1^b1),第2篇:a1*( (2^b1) - (1^b1) ) …… 第n篇:a1*( (n^b1) - ( (n-1)^b1 ) )。
ii. 对于所有的m个课题,我们可以用O(n*m)的时间预处理出写每篇论文的时间。
###***重要的在这里↓***
3.那么我们如何证明我们的做法是合法的呢?
因为若我们选择写某一个课题的第i篇论文,那么这个课题的第1~i-1篇论文都必须被选择,换句话说,写的是前i篇论文。
粗略证明如下:
i.引理:2.i 中我们求得的 第n篇论文所花时间 的表达式** a*( n^b - (n-1)^b ) ** 对于所有的整数n≥1是一个***单调递增***数列。(大家可以通过数学方法证明,也可打表观察,反正当时是YY出来的,后来才去证明)
ii.从1 中我们得到了一个**有序**的序列(递增),对于序列中第i个元素,前i-1个元素必然小于它,用题目中信息来解释:第i个元素代表了写**某一篇**论文所用的时间,前i-1个元素代表 所有 花的时间少于(等于)这一篇论文的论文所用的时间。
假设这一篇论文为课题**j**的第***k***篇论文,那么根据引理,我们得知在上述有序序列的前***i-1***项中,必然包含了课题**j**的前***k-1***篇论文(因为它们所用的时间一定比第***k***篇论文短)。
iii.至此,我们证明了这个做法的正确性。
4. 预处理加上排序,这个算法的时间复杂度为O(m*n * lg(n*m) )。
5. 若牛X的人可以用堆优化,使得总时间复杂度为O(n*lg(m))。具体原理及实现本文不再赘述。在此附上AC代码:
###block code
```
#include <cstdio>
#include <algorithm>
using namespace std;
int n, m, a, b;
long long s[25 * 200], ans;
long long power(int x, int y) {
long long res = 1, tmp = x;
while (y) {
if (y & 1) res *= tmp;
tmp *= tmp;
y >>= 1;
}
return res;
}int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d%d", &a, &b);
for (int j = 0; j < n; j++) s[i * n + j] = a * (power(j + 1, b) - power(j, b));
}
//nth_element(s, s+n, s+m*n);
sort(s, s + n * m);
ans = 0;
for (int i = 0; i < n; i++) ans += s[i];
printf("%lld\n", ans);
return 0;
}
``` -
12020-05-15 22:44:38@
//本来思路乱七八糟,想先试一下,下一个测试点再来写的,没想到直接就A了。
//因为本人菜鸡所以适合新手理解
上代码:
#include<bits/stdc++.h> using namespace std; long long f[21][300],n,m,j,k,A[210],B[210],sum[10000],ans=0; //f[a][b]意思是前a个课题写b篇的最大值 int main() { long long int p,a,b,c,d,e; cin>>m>>n; for(a=1;a<=n;a++)cin>>A[a]>>B[a];//输入不解释 for(a=1;a<=n;a++)//前a个课题 { for(b=1;b<=m;b++)//选b篇写 { for(c=0;c<=b;c++)//1.见下 { p=A[a]*pow(c,B[a]);//当前的值 if(f[a][b]==0||a==1)f[a][b]=f[a-1][b-c]+p; else//因为当f[a][b]初始赋值或a=1需要特判 f[a][b]=min(f[a-1][b-c]+p,f[a][b]);//状态转移 } } } cout<<f[n][m]; }
在第a篇中写0篇 f[a][b]=min(f[a-1][b]+p,f[a][b])//p见代码
在第a篇中写1篇 f[a][b]=min(f[a-1][b-1]+p,f[a][b])
在第a篇中写2篇 f[a][b]=min(f[a-1][b-2]+p,f[a][b])
在第a篇中写c篇 f[a][b]=min(f[a-1][b-c]+p,f[a][b])
因为已经保证前面的数组都是最大值,所以就是判断在a中选篇数再加上
前一篇文章a-c的最大值。
-
12016-01-29 11:35:40@
注意数据类型用long long,我用了int wa了三次= =
-
02017-12-09 22:27:54@
一定要记得用long long!!!
-
02017-01-22 15:58:56@
//神奇的程序
```C++
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <limits>
using namespace std;struct node1
{
int a,b;
}a[21];int main()
{
int n,m;
double c[21][201],f[21][201];
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].a,&a[i].b);
for (int j=1;j<=n;j++)
c[i][j]=double(a[i].a)*pow(double(j),double(a[i].b));
}
memset(f,0,sizeof(f));
for (int i=0;i<=m;i++)
for (int j=1;j<=n;j++)
f[i][j]=(numeric_limits<double>::max)();
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
{
f[i][j]=min(f[i][j],f[i-1][j]);
for (int k=1;k<=j;k++)
f[i][j]=min(f[i][j],f[i-1][j-k]+c[i][k]);
}
printf("%.0lf\n",f[m][n]);
}
``` -
02016-11-21 19:50:03@
××sdgsfg××
-
02016-11-08 20:20:28@
-
02015-08-02 18:14:02@
program a1198;
var
i,j,k,l,n,m,ii,jj:longint;
a,b:array[0..200]of int64; kk,ll:int64;
f:array[0..100,0..2000]of int64;
function he(x,y:longint):int64;
var
p:longint; q:int64;
begin
q:=1;
for p:=1 to y do
q:=q*x;
he:=q;
end;
begin
//assign(input,'1.txt'); reset(input);
readln(n,m);
for i:=1 to m do
readln(a[i],b[i]);
for i:=1 to n do
f[1,i]:=a[1]*he(i,b[1]);
for i:=2 to m do
for j:=1 to n do
begin
kk:=maxlongint;
for k:=0 to j do
begin
ii:=j-k;
ll:=f[i-1,k]+a[i]*he(ii,b[i]);
if (ll<kk) then kk:=ll;
end;
f[i,j]:=kk+f[i,j];
end;
writeln(f[m,n]);
end. -
02015-08-01 22:58:11@
都是pow函数惹的祸啊!!!
Wrong Answer:
###
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;#define MAX 2147483647
int n, m;
int f[25][20005];int main(int argc, const char *argv[])
{
for (int i = 0; i <= 20; ++i)
for (int j = 0; j <= 40000; ++j)
f[i][j] = MAX;
f[0][0] = 0;
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i)
{
int a, b;
scanf("%d %d", &a, &b);
for (int j = 0; j <= n; ++j)
{
int min = MAX;
for (int k = 0; k <= j; ++k)
{
long long p = (long long)(f[i - 1][j - k]) + a * (long long)(pow(k, b));
if (p < (long long)(min))
min = (int)p;
}
f[i][j] = min;
}
}
printf("%d\n", f[m][n]);
return 0;
}Accepted:
###
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;#define MAX 2147483647
int n, m;
int f[25][20005];long long val(long long k, long long b)
{
long long ans = 1;
for (int i = 1; i <= b; ++i)
ans *= k;
return ans;
}
int main(int argc, const char *argv[])
{
for (int i = 0; i <= 20; ++i)
for (int j = 0; j <= 40000; ++j)
f[i][j] = MAX;
f[0][0] = 0;
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++i)
{
int a, b;
scanf("%d %d", &a, &b);
for (int j = 0; j <= n; ++j)
{
int min = MAX;
for (int k = 0; k <= j; ++k)
{
long long p = (long long)(f[i - 1][j - k]) + a * (long long)(val(k, b));
if (p < (long long)(min))
min = (int)p;
}
f[i][j] = min;
}
}
printf("%d\n", f[m][n]);
return 0;
} -
02015-06-11 08:45:13@
我只想说,注意数据范围。。。
-
02015-01-22 23:04:56@
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define MAXL 10001long long dp[MAXL], V, n, w, a, b;
long long value(long long a, long long k, long long b);int main()
{
cin >> V >> n;
for (int i = 1; i <= n; i++)
{
cin >> a >> b;
if (i == 1)
{
for (int i = 1; i <= V; i++)
dp[i] = value(a, i, b);
continue;
}
for (int j = V; j >= 1; j--)
for (int k = 1; k <= V; k++)
dp[j] = min(dp[j - k] + value(a, k, b), dp[j]);}
cout << dp[V] << endl;
}long long value(long long a, long long k, long long b)
{
long long x = 1;
for (int i = 0; i < b; i++)
x *= k;
return x * a;
}
数据很小?自己算一下就知道有多大了。全程用longlong才AC。。。
这题就是一个很标准的分组背包,连程序都跟模板差不多。。。 -
02014-11-01 11:31:58@
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;struct topic{LL A,B;}t[25];
LL n,m,f[25][205];
LL Pow(LL a,LL b)
{
LL Ans=1;
while(b)
{
if(b%2) Ans=Ans*a;
a*=a;
b/=2;
}
return Ans;
}int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>t[i].A>>t[i].B;
memset(f,0x7f7f7f7f,sizeof(f));
for(LL i=0;i<=n;i++)
f[1][i]=t[1].A*Pow(i,t[1].B);
for(int i=2;i<=m;i++)
for(int j=0;j<=n;j++)
for(int k=0;k<=j;k++)
f[i][j]=min(f[i][j],f[i-1][j-k]+t[i].A*Pow(k,t[i].B));
cout<<f[m][n]<<endl;
return 0;
} -
02014-11-01 11:16:50@
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;struct topic{LL A,B;}t[25];
LL n,m,f[25][205];
LL Pow(LL a,LL b)
{
LL Ans=1;
while(b)
{
if(b%2) Ans=Ans*a;
a*=a;
b/=2;
}
return Ans;
}int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>t[i].A>>t[i].B;
memset(f,0x7f7f7f7f,sizeof(f));
for(LL i=1;i<=n;i++)
f[1][i]=t[1].A*Pow(i,t[1].B);
for(int i=2;i<=m;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=j;k++)
f[i][j]=min(f[i][j],f[i-1][j-k]+t[i].A*Pow(k,t[i].B));
cout<<f[m][n]<<endl;
return 0;
} -
02014-08-22 13:36:58@
##思路##
\(dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + Cal(i, k))\)
dp[i][j]表示前i个主题写j篇论文的最少时间。
初始化要注意。
刚开始全部初始化为INF,WA了。有论文数是0的数据。##代码##
#include <bits/stdc++.h> #define LL long long using namespace std; const int MAXN = 200 + 5; const int INF = 0x3f3f3f3f; struct ARTC { LL a, b; }artc[MAXN]; LL dp[30][MAXN]; LL Cal(LL cur, LL num) { LL t = 1; for (int i = 0; i < artc[cur].b; i++) t *= num; return t * artc[cur].a; } int main() { //freopen("input.txt", "r", stdin); LL ntopc, npp, i, j; scanf("%lld%lld", &npp, &ntopc); for (i = 1; i <= ntopc; i++) scanf("%lld%lld", &artc[i].a, &artc[i].b); for (i = 1; i <= ntopc; i++) for (j = 1; j <= npp; j++) dp[i][j] = INF; for (i = 1; i <= npp; i++) dp[1][i] = Cal(1, i); for (i = 2; i <= ntopc; i++) for (j = 1; j <= npp; j++) { dp[i][j] = dp[i - 1][j]; for (LL k = 1; k <= j; k++) dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + Cal(i, k)); } printf("%lld\n", dp[ntopc][npp]); return 0; }
-
02014-02-23 11:14:14@
#include<cstdio>
#include<iostream>
using namespace std;
long long int A[100][201];
long long int c[100];
long long int d[100];
long long int jisuan(long long int ci,long long int i,long long int di)
{
long long int temp = 1;
for (long long int k = 1; k <= di; k++)
temp = temp * i;
return temp * ci;
}
long long int xiao(long long int a,long long int b)
{
if(a>b)
return b;
else
return a;
}int main()
{
long long int n,m;
long long int i,j,k;
cin>>n>>m;
for(i=1;i<=m;i++)
{
cin>>c[i]>>d[i];
for(j=1;j<=m;j++)
{
A[i][j]=999999999;
}
}
A[0][0]=0;for(i=1;i<=n;i++)
{
A[1][i]=jisuan(c[1],i,d[1]);
}
for(i=2;i<=m;i++)
{
for(j=1;j<=n;j++)
{
A[i][j]=A[i-1][j];
for(k=1;k<=j;k++)
{
A[i][j] = xiao(A[i][j], A[i-1][j-k]+jisuan(c[i], k, d[i]));
}
}
}
cout<<A[m][n];
return 0;
} -
02014-01-01 12:00:47@
Vijos 题解:http://hi.baidu.com/umule/item/2c997f8ed9600fdae596e017
有疑问请留言 共同进步 -
02013-11-06 09:51:47@
var
a,b:longint;
i,j,k,n,m:longint;
v:array[1..200,1..2000] of int64;
f:array[0..2000] of int64;
begin
readln(n,m);
for k:=1 to m do
begin
readln(a,b);
for i:=1 to n do
begin
v[k,i]:=a;
for j:=1 to b do
v[k,i]:=v[k,i]*i;
end;
end;
f[0]:=0;
for i:=1 to n do
f[i]:=maxlongint;
for k:=1 to m do
for i:=n-1 downto 0 do
for j:=1 to n-i do
if (f[i]+v[k,j]<f[i+j]) then f[i+j]:=f[i]+v[k,j];
writeln(f[n]);
end. -
02013-11-03 18:22:10@
//const
// ma=;
var
fa,wei,v,a,b,f:array[0..40000]of int64;
ss,t,w,m,n,x,s:int64;
i,j,k:longint;
function min(x,y:int64):int64;
begin
if x<y then min:=x else min:=y;
end;
begin
assign(input,'choose.in');
assign(output,'choose.out');
reset(input);
rewrite(output);readln(n,m);
for i:=1 to m do
readln(a[i],b[i]);
for i:=1 to m do
for j:=1 to n do
begin
x:=1;
for k:=1 to b[i] do
x:=x*j;
x:=x*a[i];
ss:=ss+1;
wei[ss]:=j;
v[ss]:=x;
fa[ss]:=i;
end;
w:=0;
fillchar(f,sizeof(f),127);
f[0]:=0;
for i:=1 to m do
begin
t:=w+1;
w:=ss;
for j:=t+1 to ss do
if fa[j]<>fa[t] then
begin
w:=j-1;
break;
end;
for j:=n downto 1 do
for k:=t to w do
if j>=wei[k] then
f[j]:=min(f[j],f[j-wei[k]]+v[k]);
end;
writeln(f[n]);close(input);
close(output);
end.
分组背包 -
02013-10-17 21:31:11@
过掉了一题很爽的题目!
想了十多分钟,总算有点思路,并一次AC了。
我个人认为这题为背包,不太恰当。
思路:我们可以设f[i,j]表示在第i个课题,结尾为第j篇论文的最小价值。
而新的状态f[x,y]:=min(f[x,y],f[i,j]+num(y-j,x));
num是一个专门计算y-i这几篇论文,全部用于x课题时,算出答案。
一共四重循环,卡着时间AC。。。
最后答案就在min(f[i,n]),i循环一边即可。
注意要用int64;
也看了下面几位大牛关于背包的题解,不太理解。虽然我的算法实现时间很丑,但是能过就行把!
DXE-SYF。
Go on! -
02013-07-21 14:00:05@
忽略算法 这个题主要有两个地方需要注意
1.初始化 初始化我们可以用第一个数据A[1]和B[1]来进行初始化,设Dp[i]表示写到第i篇论文时最少的时间数,初始化的时候可以令Dp[i]=A[1]*i^B[i],这样就不需要初始化成INF(一个接近于无穷大的数)
2.数组要大 题目当中说的n<=200,m<=20, 我严重怀疑这个真实性 当我把Dp开到1200个数时才过的P.S.真是不好意思,为这道题贡献了太多太多的WA。。。以上。。。