ztxz16如愿成为码农之后,整天的生活除了写程序还是写程序,十分苦逼。终于有一天,他意识到自己的生活太过平淡,于是决定外出旅游丰富阅历。
ztxz16生活的城市有NM个景点,可以描述成一个NM的矩形,每个景点有一个坐标(x, y) (1 <= x <= N, 1 <= y <= M)以及美观度A[x][y]和观赏所需的时间B[x][y],从一个景点(x1, y1)走到另一个景点(x2, y2)需要时间为它们之间的曼哈顿距离:|x1 - x2| +|y1 - y2|。
为了防止审美疲劳,ztxz16希望观赏的景点的的美观度是严格上升的,由于不想太早回家码代码,ztxz16希望旅游的总时间尽可能长。
对于30%的数据:1<=N<=50 , 1<=M<=50
对于60%的数据:1<=N<=300 , 1<=M<=300
对于100%的数据:1<=N<=1000 , 1<=M<=1000
0<=A[x][y]<=1000000
0<=B[x][y]<=10^9
注意:本题输入数据较大,请注意输入消耗的时间
因为矩阵的坐标对浏览的顺序没有影响而美观度才是有影响,所以用美观度排序,按美观度的顺序随便dp
(然而这样可以过似乎是因为数据水)
(正解好像还要四边形不等式优化?)
我,差点就可以A过,但是我用了堆排,每次都要删删减减那种,就T飞了
然而并不需要堆,因为没有插入操作
//#pragma GCC optimize(3)
//#pragma GCC optimize(2)
#include
#include
#include
using namespace std;
const int N=1000006;
int n,m,cnt;
long long ans;
unsigned int a[1003][1003];
long long f[N];
struct cv{
int w,x,y;
long long f;
}b[N];
inline int read(){
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
int x=0;
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
inline int abs(int a){
return (a>0?a:-a);
}
bool comp(cv a,cv b){
return a.w
ztxz16旅游归来后十分疲倦,很快就进入了梦中。
在梦中ztxz16结婚生子了,他不得不照顾小宝宝。但这实在太无聊了,于是ztxz16会在散步。梦中ztxz16住在一个类似数轴的街上,数轴上的每个整点是一个街区,每个单位时间内ztxz16可以选择向左走一个街区或者向右走一个街区,但如果他离开家超过m个单位时间小宝宝会有危险,因此ztxz16必须在距离上次在家中不超过m个单位时间内回到家中。
n个单位时间后ztxz16会醒来,他希望此时正好在家中。
ztxz16想知道散步过程可能有多少种不同的散步过程。两个散步过程被认为不同,当且仅当存在至少一个单位时刻ztxz16选择的走向不同。
对于30%的数据:2<=n<=100, 2<=m<=100
对于100%的数据:2<=n<=10^9, 2<=m<=100
n和m均为偶数
快乐递推,在线矩乘
来自题解:
用f[i]代表i时刻回到家中的方案有多少种,观察发现转移可以写成矩阵的形式,于是可以矩阵乘法快速幂转移
设f[i][j] 表示 i 时间,走到 j 格有多少种方案
对于初始的m格,暴力递推转移,即
f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i − 1 ] [ j + 1 ] f[i][j]=f[i-1][j-1]+f[i-1][j+1] f[i][j]=f[i−1][j−1]+f[i−1][j+1]
Q:欸这个由j+1的转移难道不是有后效性?[菜鸡瞪眼.jpg]
A:傻瓜每个i去更新i+1不就好了
初始化:
然而对于求出的结果,我们只关心在偶数时间回到原点的方案数
我们就把f[i][0] (i%2=0) 的值放到存答案的数组a[i][j] 里,要乘2
a[i][i-1]=1 :i时间走到i-1格只有一种方案
a[i][i]=1 :i时间走到i格只有一种方案,就是一直走
然后矩阵自乘快速幂,n/2次方
此人散步m时间回到家中可以视为,此人散步到m/2格,所以只用求此人n/2时间走到m/2格的方案
#include
#include
using namespace std;
const int mod=1000000007;
int n,m;
long long f[105][105],a[105][105];
long long ans[105][105];
void calc(long long b[105][105]){
long long d[105][105];
memset(d,0,sizeof d);
for (int i=1;i<=m/2;i++)
for (int j=1;j<=m/2;j++)
for (int k=1;k<=m/2;k++)
d[i][j]=(d[i][j]+ans[i][k]*b[k][j])%mod;
memcpy(ans,d,sizeof d);
}
void dfs(int x){
if (x==0) return;
if (x%2==0) dfs(x/2); else dfs(x-1);
if (x%2==0) calc(ans); else calc(a);
}
int main(){
scanf("%d%d",&n,&m);
f[1][1]=1;
for (int i=1;i<=m-1;i++)
for (int j=1;j<=m/2;j++){
f[i+1][j+1]=(f[i+1][j+1]+f[i][j])%mod;
f[i+1][j-1]=(f[i+1][j-1]+f[i][j])%mod;
}
for (int i=2;i<=m/2;i++) a[i][i-1]=1;
for (int i=1;i<=m/2;i++) a[1][i]=(f[i*2][0]*2)%mod;
for (int i=1;i<=m/2;i++) ans[i][i]=1;
dfs(n/2);
printf("%lld",ans[1][1]);
}
ztxz16从小立志成为码农,因此一直对数的二进制表示很感兴趣。今天的数学课上,ztxz16学习了等差数列的相关知识。我们知道,一个等差数列可以用三个数A,B,N表示成如下形式:
B + A, B + 2 * A, B + 3 * A, …, B + N * A
ztxz16想知道对于一个给定的等差数列,把其中每一项用二进制表示后,一共有多少位是1,但他的智商太低无法算出此题,因此寻求你的帮助。
对于30%的数据:
1<=T<=20 , 1<=A<=10000 , 1<=B<=10^16 , 1<=N<=10^3
对于60%的数据:
1<=T<=20 , 1<=A<=10000 , 1<=B<=10^16 , 1<=N<=10^9
对于100%的数据:
1<=T<=20 , 1<=A<=10000 , 1<=B<=10^16 , 1<=N<=10^12
然后女主就和男主在一起了
然后我最爱的男二就死掉了
然后我第二爱的男三就独守天下了
整本书我明明最不喜欢男主好吗呜呜呜
嘤嘤嘤,你们明明有机会的,为什么不?!!
害得我一想起来就伤心QAQ