1. 程式人生 > >2014-5-10 NOIP模擬賽 by coolyangzc

2014-5-10 NOIP模擬賽 by coolyangzc

[1] clas 表示 格式 不同的 tdi 命令 正整數 style

Problem 1 機器人(robot.cpp/c/pas)

【題目描述】

早苗入手了最新的Gundam模型。最新款自然有著與以往不同的功能,那就是它能夠自動行走,厲害吧。

早苗的新模型可以按照輸入的命令進行移動,命令包括‘E’、‘S’、‘W’、‘N’四種,分別對應東南西北。執行某個命令時,它會向對應方向移動一個單位。作為新型機器人,它可以執行命令串。對於輸入的命令串,每一秒它會按命令行動一次。執行完命令串的最後一個命令後,會自動從頭開始循環。在0時刻時機器人位於(0,0)。求T秒後機器人所在位置坐標。

【輸入格式】

1行:一個字符串,表示早苗輸入的命令串,保證至少有1個命令

2行:一個正整數T

【輸出格式】

2個整數,表示T秒時,機器人的坐標。

【樣例輸入】

NSWWNSNEEWN

12

【樣例輸出】

-1 3

【數據範圍】

對於60%的數據 T<=500,000 且命令串長度<=5,000

對於100%的數據 T<=2,000,000,000 且命令串長度<=5,000

【註意】

向東移動,坐標改變改變為(X+1,Y);

向南移動,坐標改變改變為(X,Y-1);

向西移動,坐標改變改變為(X-1,Y);

向北移動,坐標改變改變為(X,Y+1);

/*
    求出第一次執行完所有命令後的位置,這就是執行完一次命令的相對位移,在求他的時候順便記錄下走每一步的相對位移,以後就可以直接用了
*/ #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,t,x,y; char s[5010]; struct node{ int x,y; }pos[5010];//pos[i]表示走i步到達的地點 int main(){ freopen("robot.in","r",stdin); freopen("robot.out","w",stdout); scanf("%s",s+1);scanf("%d"
,&t); n=strlen(s+1); for(int i=1;i<=n;i++){ if(s[i]==E)pos[i].x=pos[i-1].x+1,pos[i].y=pos[i-1].y; if(s[i]==S)pos[i].x=pos[i-1].x,pos[i].y=pos[i-1].y-1; if(s[i]==W)pos[i].x=pos[i-1].x-1,pos[i].y=pos[i-1].y; if(s[i]==N)pos[i].x=pos[i-1].x,pos[i].y=pos[i-1].y+1; } int bei=t/n,yu=t%n; x+=pos[n].x*bei;y+=pos[n].y*bei; x+=pos[yu].x;y+=pos[yu].y; printf("%d %d",x,y); }

Problem 2 數列(seq.cpp/c/pas)

【題目描述】

a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1] (x>3)

a數列的第n項對1000000007(10^9+7)取余的值。

【輸入格式】

第一行一個整數T,表示詢問個數。

以下T行,每行一個正整數n。

【輸出格式】

每行輸出一個非負整數表示答案。

【樣例輸入】

3

6

8

10

【樣例輸出】

4

9

19

【數據範圍】

對於30%的數據 n<=100;

對於60%的數據 n<=2*10^7;

對於100%的數據 T<=100,n<=2*10^9;

做這個題讓我當了一次嘴巴選手

不難發現,它和斐波那契數列的遞推式有幾分相似

於是想到矩陣快速冪(有誰第一眼看見這個題的時候暴力找規律了。。)

矩陣怎麽推的?

先看看斐波那契數列的矩陣是怎麽推得

f[i]=1*f[i-1]+1*f[i-2]

f[i-1]=1*f[i-1]+0*f[i-2]

所以矩陣就是

1 1

1 0

也就可以寫成

技術分享

技術分享

所以我們同樣來推一下這個題的矩陣

f[i]=1*f[i-1]+0*f[i-2]+1*f[i-3]

f[i-1]=1*f[i-1]+0*f[i-2]+0*f[i-3]

f[i-2]=0*f[i-1]+1*f[i-2]+0*f[i-3]

矩陣為

1 0 1

1 0 0

0 1 0

剩下的同理

然後就是矩陣快速冪的代碼問題了,我怎麽這麽菜啊

所以還是看黃學長的代碼吧

我思路應該沒錯的,不過黃學長代碼和我想的不太一樣

這次照著多打幾遍,下次自己寫

#include<cstdio>
#include<cstring>
const int mo=1000000007;
typedef long long arr[3][3];
int n,T;
long long ans;
arr opt={{0,0,1},{1,0,0},{0,1,1}},b,t;
inline void mul(arr a,arr b,arr c)
{
    memset(t,0,sizeof(t));
    for(int k=0;k<3;k++)
        for(int i=0;i<3;i++)
            if (a[i][k])
                for(int j=0;j<3;j++)
                    t[i][j]=t[i][j]+a[i][k]*b[k][j];
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if (t[i][j]<mo) c[i][j]=t[i][j];
            else c[i][j]=t[i][j]%mo;
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    for(scanf("%d",&T);T;T--)
    {
        scanf("%d",&n);
        arr a={{1,0,0},{0,1,0},{0,0,1}};
        memcpy(b,opt,sizeof(b));
        for(n-=3;n>0;n>>=1)
        {
            if (n&1) mul(a,b,a);
            mul(b,b,b);
        }
        ans=(a[2][0]+a[2][1]+a[2][2])%mo;
        printf("%d\n",ans);
    }
    return 0;
}

Problem 3 蟲洞(holes.cpp/c/pas)

【題目描述】

N個蟲洞,M條單向躍遷路徑。從一個蟲洞沿躍遷路徑到另一個蟲洞需要消耗一定量的燃料和1單位時間。蟲洞有白洞和黑洞之分。設一條躍遷路徑兩端的蟲洞質量差為delta。

1.從白洞躍遷到黑洞,消耗的燃料值減少delta,若該條路徑消耗的燃料值變為負數的話,取為0。

2.從黑洞躍遷到白洞,消耗的燃料值增加delta。

3.路徑兩端均為黑洞或白洞,消耗的燃料值不變化。

作為壓軸題,自然不會是如此簡單的最短路問題,所以每過1單位時間黑洞變為白洞,白洞變為黑洞。在飛行過程中,可以選擇在一個蟲洞停留1個單位時間,如果當前為白洞,則不消耗燃料,否則消耗s[i]的燃料。現在請你求出從蟲洞1到N最少的燃料消耗,保證一定存在1到N的路線。

【輸入格式】

1行:2個正整數N,M

2行:N個整數,第i個為0表示蟲洞i開始時為白洞,1表示黑洞。

3行:N個整數,第i個數表示蟲洞i的質量w[i]。

4行:N個整數,第i個數表示在蟲洞i停留消耗的燃料s[i]。

5..M+4行:每行3個整數,u,v,k,表示在沒有影響的情況下,從蟲洞u到蟲洞v需要消耗燃料k。

【輸出格式】

一個整數,表示最少的燃料消耗。

【樣例輸入】

4 5

1 0 1 0

10 10 100 10

5 20 15 10

1 2 30

2 3 40

1 3 20

1 4 200

3 4 200

【樣例輸出】

130

【數據範圍】

對於30%的數據: 1<=N<=100,1<=M<=500

對於60%的數據: 1<=N<=1000,1<=M<=5000

對於100%的數據: 1<=N<=5000,1<=M<=30000

其中20%的數據為1<=N<=3000的鏈

1<=u,v<=N, 1<=k,w[i],s[i]<=200

【樣例說明】

按照1->3->4的路線。

2014-5-10 NOIP模擬賽 by coolyangzc