文章目錄
0 旅遊(travel)
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 <cstdio>
#include <cstring>
#include <algorithm>
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<b.w;
}
int main(){
n=read();m=read();
for (register int i=1;i<=n;i++){
for (register int j=1;j<=m;j++){
a[i][j]=read();
}
}
for (register int i=1;i<=n;i++){
for (register int j=1;j<=m;j++){
int c=read();
if (c==0&&a[i][j]==0) continue;
b[++cnt].w=a[i][j],
b[cnt].x=i,b[cnt].y=j,b[cnt].f=c;
}
}
sort(b+1,b+1+cnt,comp);
int lr=1,ls=0;
for (int i=1;i<=cnt;){
int k=b[i].w;
while (k==b[i].w){
int kk=b[i].f;
for (register int j=lr;j<=ls;j++)
b[i].f=(long long)(b[i].f<b[j].f+abs(b[j].x-b[i].x)+abs(b[j].y-b[i].y)+kk?
b[j].f+abs(b[j].x-b[i].x)+abs(b[j].y-b[i].y)+kk:b[i].f);
i++;
}
lr=ls+1,ls=i-1;
}
for (int i=lr;i<=cnt;i++)
ans=(ans<b[i].f?b[i].f:ans);
printf("%lld",ans);
}
1 做夢(dream)
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格,暴力遞推轉移,即
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 <cstdio>
#include <cstring>
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]);
}
2 數數(count)
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