There are $n$ courses in the course selection system of Marjar University. The $i$-th course is described by two values: happiness $Hi$ and credit $Ci$. If a student selects $m$ courses $x1$, $x2$, ..., $xm$, then his comfort level of the semester can be defined as follows:
$$(\sum^m_{i=1}H_{x_i})^2-(\sum^m_{i=1}H_{x_i})\times (\sum^m_{i=1}C_{x_i})-(\sum^m_{i=1}C_{x_i})^2$$
Edward, a student in Marjar University, wants to select some courses (also he can select no courses, then his comfort level is $0$) to maximize his comfort level. Can you help him?
There are multiple test cases. The first line of input contains an integer $T$, indicating the number of test cases. For each test case:
The first line contains a integer $n$ $(1 ≤ n ≤ 500)$ -- the number of cources.
Each of the next $n$ lines contains two integers $H_i$ and $C_i$ $(1 ≤ H_i ≤ 10000, 1 ≤ C_i ≤ 100)$.
It is guaranteed that the sum of all $n$ does not exceed $5000$.
We kindly remind you that this problem contains large I/O file, so it's recommended to use a faster I/O method. For example, you can use scanf/printf instead of cin/cout in C++.
For each case, you should output one integer denoting the maximum comfort.
2
3
10 1
5 1
2 10
2
1 10
2 10191
0For the first case, Edward should select the first and second courses.
For the second case, Edward should select no courses.
[button color="success" url="https://vjudge.net/problem/ZOJ-3956" outline="default" target="_blank"]vjudge_ZOJ-3956-Course Selection System[/button]
通过题目我们可以了解到在一定的$C$下$H$越高,$comfort level$就越高,所以我们应该求出在所有可能的$C$值下最高的$H$值,因为$C$的最大值并不大,题目给出不超过$5000$;因此我们可以创建一个数组来进行0/1背包的求解。求出每个$C$下最高的$H$,注意$H$的范围,所以int的范围是不够表达comfortable的值的,要用long long int,求出所有最高$H$后再进行计算,求出所有$C$中的最优解。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
# define MaxN 500+5
# define MaxC 500*100+5
typedef long long int LL;
LL max(LL a,LL b)
{
return a>b ? a:b;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int dp[MaxC];
int H[MaxN];
int C[MaxN];
memset(dp,0,sizeof dp);
int N;
int i;
int TopC=0;
scanf("%d",&N);
for(i=1;i<=N;i++)
{
scanf("%d",&H[i]);
scanf("%d",&C[i]);
TopC+=C[i];
}
for(i=1;i<=N;i++)
{
int l;
for(l=TopC;l>=C[i];--l)
dp[l]=max(dp[l],dp[l-C[i]]+H[i]);
}
LL max1=0;
for(i=0;i<=TopC;i++)
max1=max(1LL*dp[i]*dp[i]-1LL*dp[i]*i-1LL*i*i,max1);
printf("%lld",max1);
if(T!=0)
printf("\n");
}
return 0;
}
]]>A seven segment display, or seven segment indicator, is a form of electronic display device for displaying decimal numerals that is an alternative to the more complex dot matrix displays. Seven segment displays are widely used in digital clocks, electronic meters, basic calculators, and other electronic devices that display numerical information.
Edward, a student in Marjar University, is studying the course "Logic and Computer Design Fundamentals" this semester. He bought an eight-digit seven segment display component to make a hexadecimal counter for his course project.
In order to display a hexadecimal number, the seven segment display component needs to consume some electrical energy. The total energy cost for display a hexadecimal number on the component is the sum of the energy cost for displaying each digit of the number. Edward found the following table on the Internet, which describes the energy cost for display each kind of digit.

For example, in order to display the hexadecimal number "$5A8BEF67$" on the component for one second, $5 + 6 + 7 + 5 + 5 + 4 + 6 + 3 = 41$ units of energy will be consumed.
Edward's hexadecimal counter works as follows:
There are multiple test cases. The first line of input contains an integer $T$ $(1 ≤ T ≤ 10^5)$, indicating the number of test cases. For each test case:
The first and only line contains an integer $n (1 ≤ n ≤ 10^9)$ and a capitalized eight-digit hexadecimal number $m (00000000 ≤ m ≤ FFFFFFFF)$, their meanings are described above.
We kindly remind you that this problem contains large I/O file, so it's recommended to use a faster I/O method. For example, you can use scanf/printf instead of cin/cout in C++.
For each test case output one line, indicating the total units of energy consumed by the eight-digit seven segment display component.
3
5 89ABCDEF
3 FFFFFFFF
7 00000000208
124
327For the first test case, the counter will display $5$ hexadecimal numbers $(89ABCDEF, 89ABCDF0, 89ABCDF1, 89ABCDF2, 89ABCDF3)$ in $5$ seconds. The total units of energy cost is $$\begin{align}(7 + 6 + 6 + 5 + 4 + 5 + 5 + 4) + (7 + 6 + 6 + 5 + 4 + 5 + 4 + 6) \\ + (7 + 6 + 6 + 5 + 4 + 5 + 4 + 2) + (7 + 6 + 6 + 5 + 4 + 5 + 4 + 5) \\ + (7 + 6 + 6 + 5 + 4 + 5 + 4 + 5) = 208\end{align}$$.
For the second test case, the counter will display $3$ hexadecimal numbers $(FFFFFFFF, 00000000, 00000001)$ in $3$ seconds. The total units of energy cost is $$\begin{align}(4 + 4 + 4 + 4 + 4 + 4 + 4 + 4) + (6 + 6 + 6 + 6 + 6 + 6 + 6 + 6) \\ + (6 + 6 + 6 + 6 + 6 + 6 + 6 + 2) = 124\end{align}$$.
[button color="success" url="https://vjudge.net/problem/ZOJ-3962" outline="default" target="_blank"]vjudge_ZOJ_3962_Seven Segment Display[/button]
数位DP,有点像打表的感觉,但又没那么容易,首先判断一下$n$秒以后有没有超过$0xffffffff$如果超了,那么结果就等于
$\begin{align}(0xffffffff的权值-((初始值-1的权值)- (初始值加上n-1秒-(0xffffffff+1)后的权值)))\end{align}$若没超过那就好算了$(初始值+n-1的权值-初始值-1的权值)$没看懂的可以自己画个图试一下,就是如果超过了$0xffffffff$就求补集否则,直接求。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
typedef long long LL;
int cost[16]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
const LL mod =(LL)0xffffffff+1;
int a[20]; //存储16进制数字(字母转化为数字)
LL dp[20][1005]; //数位dp,名字不用管啦,看代码就知道了
LL change(char *str) //将字符串组合成一个16进制的数
{
LL tmp=0;
for(int i=0;i<8;i++)
{
if(str[i]>='0' && str[i]<='9')
tmp=tmp*16+str[i]-'0';
else
tmp=tmp*16+str[i]-'A'+10;
}
return tmp;
}
LL dfs(int pos, LL sum,int limit)
{
if(pos<0) //若最低位已经计算完成
return sum;
if(!limit && dp[pos][sum]!=-1) //效率优化,极大极大的优化的
return dp[pos][sum];
int up=limit ? a[pos]:15;
LL tmp=0;
for(int i=0;i<=up;i++) //计算此位上所有可能的数字的权值和,类似打表
tmp+=dfs(pos-1,sum+cost[i],limit&&(i==a[pos]));
if(!limit )
dp[pos][sum]=tmp; //记录可能会重复利用的数字
return tmp;
}
LL solve(LL x)//将整个16进制数各个位数拆分
{
int pos=0;
memset(a,0,sizeof(a)); //因为有多组数据,计算前先清空之前计算过的数据
while(x)
{
a[pos++]=x%16;
x/=16;
}
return dfs(7,0,1); //由于数组中各个位数排序位置与大数相反,所以最高位为下标为7的时候
}
int main()
{
int T;
scanf("%d",&T);
memset(dp,-1,sizeof(dp));
while(T--)
{
int setp;
char str[20];
scanf("%d %s",&setp,str);
setp--;
LL l=change(str); //将16进制字符转换为10进制数字
LL b=setp/mod; //每从0x00000000到0xffffffff是一个循环节,超过的用倍数统计即可
if(l+setp>=mod)
{
LL r=(l+setp)%mod;
printf("%lld\n",(b+1)*solve((LL)0xffffffff)-(solve(l-1)-solve(r)));
}
else
{
LL r=l+setp;
printf("%lld\n",solve(r)-solve(l-1));
}
}
return 0;
}
]]>杭州人称那些傻乎乎粘嗒嗒的人为$62$(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
$62315$ $73418$ $88914$
都属于不吉利号码。但是,$61152$虽然含有$6$和$2$,但不是$62$连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
输入的都是整数对$n$、$m$$(0<n≤m<1000000)$,如果遇到都是$0$的整数对,则输入结束。
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
1 100
0 080[button color="success" url="https://vjudge.net/problem/HDU-2089" outline="default" target="_blank"]vjudge_HDU-2089[/button]
数位DP全搜里,总共就三个状态,一个是上一个数字是6但是搜到现在还没确定这个车牌号没法用的,意思就是之后这个车牌号有可能会被废掉,一种状态是已经确定了这个车牌号没法用了,还有一个就是上一个数字不是6并且搜到现在车牌号还没被废掉,记录这三种状态的数字,可以大大减少DP时间。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
typedef long long LL;
int a[10];
int dp[10][3]; //只需记录三种状态,分析里有解释
LL dfs(int last,int pos,int limit,int symbol)
{
if(symbol==1 && !limit)
return pow(10,pos);
if(pos<1)
if(symbol==1)
return 1;
else
return 0;
if(!limit)
{
if(symbol==1 && dp[pos][0]!=-1)
return dp[pos][0];
if(symbol==0 && last==6 && dp[pos][1]!=-1)
return dp[pos][1];
if(symbol==0 && last != 6 && dp[pos][2]!=-1)
return dp[pos][2];
}
int up=limit ? a[pos]:9;
int i;
LL tmp=0;
for(i=0;i<=up;i++)
tmp+=dfs(i,pos-1,limit && i==a[pos],(i==4 ||(last==6 && i==2)) || symbol);
if(!limit)
{
if(symbol==1 && dp[pos][0]!=-1)
dp[pos][0]=tmp;
if(symbol==0 && last==6 && dp[pos][1]!=-1)
dp[pos][1]=tmp;
if(symbol==0 && last != 6 && dp[pos][2]!=-1)
dp[pos][2]=tmp;
}
return tmp;
}
LL solve(LL x)
{
memset(a,-1,sizeof(a));
int a_=1;
while(x>0)
{
a[a_++]=x%10;
x/=10;
}
return dfs(0,a_-1,1,0);
}
int main()
{
LL n,m;
memset(dp,-1,sizeof(dp));
while(scanf("%lld%lld",&n,&m)!=EOF)
{
if(n==0 && m==0)
break;
printf("%lld\n",m-n+1-(solve(m)-solve(n-1)));
}
return 0;
}
]]>Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well-known, that the city will conduct one of the Formula 1 events. Surely, for such an important thing a new race circuit should be built as well as hotels, restaurants, international airport - everything for Formula 1 fans, who will flood the city soon. But when all the hotels and a half of the restaurants were built, it appeared, that at the site for the future circuit a lot of gophers lived in their holes. Since we like animals very much, ecologists will never allow to build the race circuit over the holes. So now the mayor is sitting sadly in his office and looking at the map of the circuit with all the holes plotted on it.
Who will be smart enough to draw a plan of the circuit and keep the city from inevitable disgrace? Of course, only true professionals - battle-hardened programmers from the first team of local technical university!.. But our heroes were not looking for easy life and set much more difficult problem: "Certainly, our mayor will be glad, if we find how many ways of building the circuit are there!" - they said.
It should be said, that the circuit in Vologda is going to be rather simple. It will be a rectangle $N* M$ cells in size with a single circuit segment built through each cell. Each segment should be parallel to one of rectangle's sides, so only right-angled bends may be on the circuit. At the picture below two samples are given for $N = M = 4$ (gray squares mean gopher holes, and the bold black line means the race circuit). There are no other ways to build the circuit here.

The first line contains the integer numbers $N$ and $M (2 ≤ N, M ≤ 12)$. Each of the next $N$ lines contains $M$ characters, which are the corresponding cells of the rectangle. Character "$.$" (full stop) means a cell, where a segment of the race circuit should be built, and character "$*$" (asterisk) - a cell, where a gopher hole is located. There are at least $4$ cells without gopher holes.
You should output the desired number of ways. It is guaranteed, that it does not exceed $2^{63}-1$.
4 4
**..
....
....
....4 4
....
....
....
....26有一个$n\times m$的棋盘,'$.$'能走,'*'不能走,请问有多少种不同的走法能够经过所有点并且每个每个点不重复并且路径形成一个 回路 ,即有多少个 哈密顿回路。
[button color="success" url="https://vjudge.net/problem/URAL-1519" outline="default" target="_blank"]👉vjudge-ural_1519_Formula 1[/button]
kuangbin系列插头dp入门题。佩服cdq大佬高中就能够想出这种算法。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll ;
ll a[1594323+10];
ll newa[1594323+10];
char mg[15][15];
queue<int>QQ[2];
bool flag[1594323+10];
int my_min(int a,int b)
{
return a<b ?a:b;
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
{
memset(newa,0,sizeof(newa));
memset(a,0,sizeof(a));
memset(flag,false,sizeof(flag));
int tp=1;
for(int i=0;i<=m;i++)
tp*=3;
int y=tp/3;
int x=y/3;
a[0]=1;
int r,c;
r=c=-1;
QQ[0].push(0);
for(int i=0;i<n;i++)
{
scanf("%s",mg[i]);
for(int k=0;k<m;k++)
{
if(mg[i][k]=='.')
{
r=i;
c=k;
}
}
}
// printf("%d %d\n",r,c);
if(r==-1)
cout<<0<<endl;
else
{
for(int i=0;i<n;i++)
for(int k=0;k<m;k++)
{
while(!QQ[0].empty())
{
int p=QQ[0].front() ;
QQ[0].pop();
int sjt=p%3;
int zjt=p/y;
int np=(p%y)/3;
if(mg[i][k]=='*')
{
if(sjt==zjt && sjt==0)
{
newa[np]+=a[p];
if(flag[np]==false)
{
flag[np]=true;
QQ[1].push(np);
}
}
}
else
{
if((sjt==0 &&zjt!=0 ) || (sjt!=0 && zjt==0))
{
int ljt;
if(zjt!=0)
ljt=zjt;
else
ljt=sjt;
newa[np+ljt*x]+=a[p];
if(flag[np+ljt*x]==false)
{
flag[np+ljt*x]=true;
QQ[1].push(np+ljt*x);
}
if(k!=m-1)
{
newa[np+ljt*y]+=a[p];
if(flag[np+ljt*y]==false)
{
flag[np+ljt*y]=true;
QQ[1].push(np+ljt*y);
}
}
}
else
if(sjt==0 && zjt==0)
{
if(k!=m-1)
{
newa[np+y*2+x*1]+=a[p];
if(flag[np+y*2+x*1]==false)
{
flag[np+y*2+x*1]=true;
QQ[1].push(np+y*2+x*1);
}
}
}
else
{
if(!(i==r && k==c))
{
if(!(sjt==2 && zjt==1))
{
if(sjt==2 && zjt==2)
{
int yy=y;
int zkh=0;
int ykh=1;
while(1)
{
if((np%(yy*3))/yy==1)
zkh++;
if((np%(yy*3))/yy==2)
ykh++;
if(ykh==zkh)
break;
yy/=3;
}
newa[np+yy]+=a[p];
if(flag[np+yy]==false)
{
flag[np+yy]=true;
QQ[1].push(np+yy);
}
}
else
if(sjt==1 && zjt==1)
{
int yy=1;
int zkh=1;
int ykh=0;
while(1)
{
if((np%(yy*3)/yy)==1)
zkh++;
if((np%(yy*3)/yy)==2)
ykh++;
if(ykh==zkh)
break;
yy*=3;
}
newa[np-yy]+=a[p];
if(flag[np-yy]==false)
{
flag[np-yy]=true;
QQ[1].push(np-yy);
}
}
else
{
newa[np]+=a[p];
if(flag[np]==false)
{
flag[np]=true;
QQ[1].push(np);
}
}
}
}
else
{
newa[np]+=a[p];
if(flag[np]==false)
{
flag[np]=true;
QQ[1].push(np);
}
}
}
}
a[p]=0;
}
while(!QQ[1].empty())
{
int num=QQ[1].front();
QQ[1].pop();
a[num]=newa[num];
newa[num]=0;
flag[num]=false;
QQ[0].push(num);
}
}
cout<<a[0]<<endl;
}
}
return 0;
}
]]>