華東交通大學2013年ACM“雙基”程序設計競賽 解題報告

華東交通大學2013年ACM“雙基”程序設計競賽 最終排名:http://acm.hdu.edu.cn/diy/contest_ranklist.php?cid=20955&page=1

華東交通大學2013年ACM“雙基”程序設計競賽賽後重掛(對題目感興趣的同學可以去該網址重新提交代碼進行測試):http://acm.hdu.edu.cn/diy/contest_show.php?cid=21280

下面給出所有題目的思路及源代碼:

神犇的悲慘一生

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 432   Accepted Submission(s) : 243

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

傳說中有位神犇,居住在公元250年前的壓力山大,由於神犇一貫低調,所以人們連他活了多少歲都不知道,好在XXXX文獻上有段關於他生平細節的文字。。
XX神犇的一生,幼年佔了1/6,又過了1/12的青春期,又談了1/6的戀愛後結婚,m年後生了個孩子,名叫神牛,神牛比神犇先死n年,神牛的壽命是神犇的一半
現在人們邀請作爲下一任神犇的你,算出這位神犇活了多少歲。。(神犇的命都是好長的)

注意
請採用下面這種格式輸入
#include<cstdio>
using namespace std;

int main()
{
int n , m;
while(scanf("%d%d",&n,&m) != EOF)
{

}
return 0;
}

Input

多組數據每組數據輸入m,n,意思爲題目所描述的。(0 < n , m <= 100)

Output

輸一行出解(神犇的年齡)

Sample Input

50 70

Sample Output

1440

Author

moonlike


草稿紙上推算即可得出規律。
#include<cstdio>
using namespace std;

int main()
{
    int n , m;
    while(scanf("%d%d",&n,&m) != EOF)
    {
        printf("%d\n",12 * (n + m));
    }
    return 0;
}

Go shopping

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 622   Accepted Submission(s) : 35

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

最近Awell的運氣特別好,這不,他在路邊攤買彩票,居然中了大獎。秉着見者有份的原則,他準備請咱們學校ACM-ICPC訓練基地的全體隊員逛商場。

  趕巧交大旁邊有一家商場新店開張,正在進行打折促銷活動。於是,咱們所有隊員都在商場中大肆購買之後,在收銀臺前排起了長隊。

  話說回來,這家商場的打折方式有些奇怪:他們從在收銀臺前付賬的所有n位顧客中,每隔m名顧客便挑選一位顧客享受七五折優惠,其餘顧客只能享受九五折。

  爲了方便付賬,Awell拜託老闆將付賬者的姓名和付款金額打印出來,作爲參考。
  
  你需要注意的是,在收銀臺前長長的隊伍中,有的可不止是ACM隊員,同樣,還有很多交大的同學慕名前來消費。爲了區分他們,我們規定,所有ACM隊員必須在姓名前加上前綴“ACM”(不包含雙引號,且不存在非ACM隊員的同學名字前面出現ACM字樣)。

  現在,請機智的你爲Awell編寫一個小程序,算一算他總共需要花費多少錢呢?

Input

輸入數據包含多組,每組第一行有兩個整數n,m。分別代表着在收銀臺前隊伍的全部人數,以及商家將會選擇每第m位顧客打7.5折。
你可以通過
while(scanf(......)!=EOF)
{
  ……;
}
的形式進行輸入。接下來有n行,每行將會輸入消費者的姓名(長度不超過20個字符),以及他們各自消費的金額(以“元”位單位,最高可能精確到小數點後兩位)。

Output

  每組數據輸出一行,每行一個實數,表示Awell總共需要花費多少開銷。你應該注意的是,老闆只收取“角”作爲最小單位,而且他是一個錙銖必較的人,所以,如果你所付金額中存在小於0.1元的部分,那就至少要付0.1元給他(想着即將消瘦的錢包,Awell淚目中......O(∩_∩)O~~)

Sample Input

4 2
Newee 123.12
ACMAwell 100
PRO 345.5
Sirius 456.99
5 2
Newee 123.12
ACMAwell 100
PROPHET 345.5
Sirius 456.99
ACMProphetK 100

Sample Output

75.0
170.0

Author

ProphetK

按照題目要求模擬操作即可,注意因爲輸入的小數最多爲2位,乘上0.75或0.95,累加之後最多爲4位小數,所以只需要在運算結果上加上0.0499即可保證小於
0.1的可以進位。
#include<stdio.h>
int main()
{
    int n,m,i;
    double sum,buy;
    char name[25];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        sum=0;
        for(i=1;i<=n;i++)
        {
            scanf("%s%lf",name,&buy);
            if(name[0]=='A'&&name[1]=='C'&&name[2]=='M')
            {
                if(i%m==0)
                    sum+=buy*0.75;
                else
                    sum+=buy*0.95;
            }
        }
        printf("%.1f\n",sum+0.0499);
    }
    return 0;
}


中秋掛燈籠

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 44   Accepted Submission(s) : 3

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

小明的家鄉有一棵神奇的樹-二叉樹,即樹的每一個節點只有兩個分支

現在中秋節到了,鄉里需要派一個人掛n個燈籠到這個樹上(燈籠只能掛到樹的節點上),由於風俗原因,當樹上的一個節點掛了燈籠後,由這個節點開始產生的所有的分支都不準掛燈籠,已知每個燈籠都有一個重量W
而每個燈籠掛到樹上所消耗的體力是樹的根節點(地面)到燈籠的位置之間的距離L*W(兩節點之間距離爲1)
由於這個人體力有限,所以希望花費的體力最少,你能幫他算算他花費的最少體力是多少嗎?

Input

多組測試
每行首先有個n(0<=n<=10000)表示燈籠的數量,接下來一行每行有n個數表示燈籠的重量W(0<=W<=10000)
輸入以文件末尾結束

Output

對於每個測試輸出一個整數表示花費的最少體力

第二個樣例解釋

Sample Input

4
1 1 2 1
1
1

Sample Output

15
1

Author

xyyh


本題主要考察數據結構——哈夫曼樹。(瞭解哈夫曼樹請點擊)

利用c++的優先隊列很容易實現這一過程。
/*分析:
由於題目說:1.當樹上的一個節點掛了燈籠後,由這個節點開始產生的所有的分支都不準掛燈籠
2.並且掛燈籠花費的力氣是L*W,即到根的長度*權值
需要求掛完全部燈籠花費的最小力氣,這就是完完全全的Huffman Tree模型
所以只要照着Huffman Tree建立樹求最小值即可 
*/
//第二種寫法:用優先隊列
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
using namespace std;

const int MAX=10000+10;
int father[MAX*2],dp[MAX*2],s[MAX];

struct Node{
	int id,val;
	bool operator<(const Node &a)const{
		return val>a.val;
	}
}p,a,b;

void Init(int num){
    for(int i=0;i<2*num;++i){
        father[i]=i;
        dp[i]=0;
    }
}

int findset(int i){
    if(dp[i] || father[i] == i)return dp[i];
    return dp[i]=findset(father[i])+1;
}

int main(){
    int n;
    while(~scanf("%d",&n)){
    	priority_queue<Node>q;
        Init(n);
        for(int i=0;i<n;++i){
        	scanf("%d",&s[i]);
        	p.val=s[i],p.id=i;
        	q.push(p);
        }
        for(int i=0;i<n-1;++i){//做n-1次合併操作即可
            a=q.top(),q.pop();
            b=q.top(),q.pop();
            father[a.id]=father[b.id]=p.id=n+i;
            p.val=a.val+b.val;
            q.push(p);
        }
        __int64 sum=0;
        for(int i=0;i<n;++i){
            sum+=s[i]*(findset(i)+1);
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

求和

Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 47   Accepted Submission(s) : 0

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

定義一個關係:
f[n]=(1^x) * (x^1) + (2^x) * (x^2) + (3^x) * (x^3) + (4^x) * (x^4) + (5^x) * (x^5) +...+ (n^x) * (x^n)

定義另一個關係:
g[n]=k*n+b

現在給定x,k,n,b的值,求f[g[0]] + f[g[1]] + f[g[2]] + f[g[3]] + ...+ f[g[n-2]] + f[g[n-1]] + f[g[n]]
輸出對20130919取模後的值

Input

輸入有多組測試,每組測試輸入4個正整數x,k,n,b代表題目描述的變量
其中0<x<=20,k,,n,b是不超過 1,000,000,000正整數
輸入以文件末尾結束

Output

對於每組輸入請輸出 mod 20130919後的值

Sample Input

1 1 1 1
2 2 2 2

Sample Output

4
3814

Author

xyyh

/*分析:
假定f[n]=A^n;//A爲矩陣,f[n]爲A^n的某項值
則sum(f[g[n]])=f[g[0]]+f[g[1]]+...+f[g[n]]
=A^b+A^(k+b)+A^(2k+b)+A^(3k+b)+...+A^(nk+b)
=A^b+A^b(A^k+A^2k+A^3k+A^4k+...+A^nk)
將A^k看成一個新的矩陣B,則原式:
=A^b+A^b(B^1+B^2+B^3+...+B^n);//A^b,A^k用矩陣快速冪求出,括號中的用二分矩陣可求
所謂二分矩陣:A^1+A^2+A^3+A^4+A^5+A^6=(A^1+A^2+A^3)+A^3(A^1+A^2+A^3)

現在問題的關鍵轉化爲如何求矩陣A:
fn=1^x * x^1 + 2^x * x^2 +...+ n^x * x^n;
fn+1=1^x * x^1 + 2^x * x^2 +...+ n^x * x^n+(n+1)^x * x^(n+1)=fn+(n+1)^x * x^(n+1),將(n+1)^x二項式展開然後用矩陣快速冪
構造矩陣:
|1 xC(x,0) xC(x,1) xC(x,2) ... xC(x,x)|  |fn       | |f(n+1)           |
|0 xC(0,0) 0       0       ... 0      |  |x^n * n^0| |x^(n+1) * (n+1)^0|
|0 xC(1,0) xC(1,1) 0       ... 0      | *|x^n * n^1|=|x^(n+1) * (n+1)^1|
|0 xC(2,0) xC(2,1) xC(2,2) ... 0      |  |x^n * n^2| |x^(n+1) * (n+1)^2|
|...                                  |  |...      | |...              |
|0 xC(x,0) xC(x,1) xC(x,2) ... xC(x,x)|  |x^n * n^x| |x^(n+1) * (n+1)^x|
*/
//第一種方法,採用二分求A^1+A^2+A^3...+A^n
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX=20+10;
const int mod=20130919;
LL array[MAX][MAX],ans[MAX][MAX];
LL temp[MAX][MAX],sum[MAX][MAX];
int n,x,k,b;

LL C(int n,int m){
	if(m<0 || m>n)return 0;
	LL num=1;
	for(int i=1;i<=m;++i){
		num=num*(n-m+i)/i;
	}
	return num%mod;
}

void MatrixInit(LL a[MAX][MAX],LL b[MAX][MAX],int flag){
	a[0][0]=1;
	if(flag == 2)a[0][0]=b[0][0];
	//計算第一行,總共有x+2行,x+2列
	for(int j=1;j<=x+1;++j){//C(x,0)~C(x,x)所以是x+1列
		if(flag == 1)a[0][j]=x*C(x,j-1)%mod;//初始化矩陣A
		else if(flag == 0)a[0][j]=0;//初始化單位矩陣
		else a[0][j]=b[0][j];//a=b
	}
	//計算第二行到第x+2行
	for(int i=1;i<=x+1;++i){
		for(int j=0;j<=x+1;++j){
			if(flag == 1)a[i][j]=x*C(i-1,j-1)%mod;//初始化矩陣A
			else if(flag == 0)a[i][j]=(i == j);//初始化單位矩陣
			else a[i][j]=b[i][j];//a=b
		}
	}
}

void MatrixAdd(LL a[MAX][MAX],LL b[MAX][MAX]){
	for(int i=0;i<=x+1;++i){
		for(int j=0;j<=x+1;++j){
			a[i][j]=(a[i][j]+b[i][j])%mod;
		}
	}
}

void MatrixMult(LL a[MAX][MAX],LL b[MAX][MAX]){
	LL c[MAX][MAX]={0};
	for(int i=0;i<=x+1;++i){
		for(int j=0;j<=x+1;++j){
			for(int k=0;k<=x+1;++k){
				c[i][j]+=a[i][k]*b[k][j];
			}
		}
	}
	for(int i=0;i<=x+1;++i){
		for(int j=0;j<=x+1;++j)a[i][j]=c[i][j]%mod;
	}
}

void MatrixPow(int k){
	MatrixInit(sum,sum,0);//sum=1
	MatrixInit(temp,array,2);//temp=array
	while(k){
		if(k&1)MatrixMult(sum,temp);
		MatrixMult(temp,temp);
		k>>=1;
	}
}

void MatrixSum(int k){//A^1+A^2+...+A^k=(A^1+A^2+...A^k/2)+A^m(A^1+A^2+...+A^k/2)=(1+A^m)*(A^1+A^2+...A^k/2)
	if(k == 1){MatrixInit(ans,array,2);return;}//ans=A,這裏的A事上面分析的B
	MatrixSum(k/2);//A^1+A^2+...+A^k/2
	MatrixPow(k+1>>1);//A^m,m=(k+1)/2
	//k爲偶數則(1+A^m)*(A+A^2+A^3...),m=(k+1)/2
	MatrixInit(temp,temp,0);//temp=1
	MatrixAdd(temp,sum);//temp=1+A^m
	MatrixMult(ans,temp);//ans=ans*temp
	//k爲奇數則A^m+(1+A^m)*(A+A^2+A^3...),m=(k+1)/2
	if(k&1)MatrixAdd(ans,sum);//ans=A^m+ans,奇數的話A^1+A^2+...+A^k=(A^1+A^2+...A^k/2)+A^m+A^m(A^1+A^2+...+A^k/2)
}

int main(){
	while(~scanf("%d%d%d%d",&x,&k,&n,&b)){
		MatrixInit(array,array,1);//初始化array=A
		MatrixPow(k);//求sum=A^k
		MatrixInit(array,sum,2);//array=A^k=B
		MatrixSum(n);//求ans=B^1+B^2+...+B^n
		MatrixInit(array,array,1);//初始化array=A
		MatrixPow(b);//求sum=A^b
		MatrixMult(ans,sum);//ans=ans*sum=ans*A^b
		MatrixAdd(ans,sum);//ans=ans+A^b
		printf("%I64d\n",ans[0][1]);
	}
	return 0;
}

too_weak的奶酪

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 103   Accepted Submission(s) : 3

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

too_weak有一塊N x N的棋盤,棋盤上K只老鼠,會喫掉和它處於同一行或同一列的奶酪,現在too_weak想要在棋盤上儘可能多地放置奶酪,要使得too_weak放的奶酪不會被老鼠喫掉。現在不能更弱的too_weak想要知道有多少個位置不能放奶酪(有老鼠的位置除外)。

Input

輸入數據有很多組,以EOF結尾。
每組數據以兩個整數N,K。N代表棋盤的規模是N x N,K代表老鼠的數目。
接下來有K行,每行兩個數x,y。分別代表每隻老鼠的座標(下標從1開始)
1. 1 <= N<= 10^9,1<=k<=10^6
2. 1<=x,y<=10^9

Output

輸出不能放置奶酪的位置有多少個。(除去有老鼠的位置)

Sample Input

4 4
1 2
2 1
2 3
3 2

Sample Output

11

Author

moonlike

可以先統計行被佔用了多少,然後在統計列時去除對應重複的,再累加。
最後化簡表達式可得到如下結果:

numx表示不同的行數量
numy表示不同的列數量
answer =  n*(numy+numx)-1ll*numy*numx-k

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1000005;
int x[maxn],y[maxn];
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=0;i<k;++i)
           scanf("%d%d",&x[i],&y[i]);
        int numx=1,numy=1;
        sort(x,x+k);
        for(int i=1;i<k;++i)
            if(x[i]!=x[i-1]) ++numx;
       sort(y,y+k);
       for(int i=1;i<k;++i)
           if(y[i]!=y[i-1]) ++numy;
       printf("%I64d\n",1ll*n*(numy+numx)-1ll*numy*numx-k);
    }
    return 0;
}

Lentty要喫巧克力

Time Limit : 6000/2000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 57   Accepted Submission(s) : 5

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Lentty最喜歡做的事情就是喫巧克力,經常幻想擁有喫不完的巧克力,作爲一個acmer,kane出了個問題準備考考她,如果回答出來,那巧克力自然是源源不斷的啦。kane給出了一列排好的的巧克力,有的是德芙,有的是費列羅,它們都擁有不同的美味值...現在kane通過魔法更改了這些巧克力,lentty必須能指出排列中第K個是巧克力的美味值是多少和某一段巧克力中最美味的值是多少,才能喫到巧克力,否則,哼哼,就去乖乖的做題吧。現在,lentty來尋求你的幫助,你能讓poor lentty 喫上巧克力嗎?

Input

輸入數據有很多組,以EOF結尾。
每組數據以四個整數N,M。N代表初始的巧克力數目,M代表操作數。
第一行給定n,第二行含有n個正整數,代表每塊巧克力的美味值wi。
每塊巧克力的下標從0-n-1.。
操作分4種,Query x y 代表查詢某一個區間內的美味最大值。
Ask x 代表查詢某一塊巧克力的美味值。
Change x y 代表將第x塊的美味值變成y
Add x y 代表講從第x塊到第y塊巧克力的美味值分別增加1.
1. 1 <= N<= 100000
2.1<= M <= 100000
2. Wi <= 5000

Output

對於每一個Query輸出一個整數,代表區間內的美味最大值。
對於每一個Ask 輸出一個整數,代表這塊巧克力的美味值。

Sample Input

10 4
1 2 3 4 5 6 7 8 9 10
Ask 0
Change 0 1
Add 0 2
Query 0 2

Sample Output

1
4

Author

Mr.Ant

線段數的基本操作:單點更新,區間更新與最值查詢。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define lz 2*u,l,mid
#define rz 2*u+1,mid+1,r
const int maxn=100005;
int a[maxn];
int maxx[4*maxn], flag[4*maxn];

void push_down(int u, int l, int r)
{
    if(flag[u])
    {
        flag[2*u]+=flag[u];
        flag[2*u+1]+=flag[u];
        maxx[2*u]+=flag[u];
        maxx[2*u+1]+=flag[u];
        flag[u]=0;
    }
}

void build(int u, int l, int r)
{
    flag[u]=0;
    if(l==r)
    {
        maxx[u]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lz);
    build(rz);
    maxx[u]=max(maxx[2*u],maxx[2*u+1]);
}

void Update(int u, int l, int r, int tl, int tr, int c, int op)
{
    if(tl<=l&&r<=tr)
    {
        if(op==1)
        {
            flag[u]+=c;
            maxx[u]+=c;
        }
        else
        {
            maxx[u]=c;
        }
        return ;
    }
    push_down(u,l,r);
    int mid=(l+r)>>1;
    if(tr<=mid) Update(lz,tl,tr,c,op);
    else if(tl>mid) Update(rz,tl,tr,c,op);
    else
    {
        Update(lz,tl,mid,c,op);
        Update(rz,mid+1,tr,c,op);
    }
    maxx[u]=max(maxx[2*u],maxx[2*u+1]);
}

int Query(int u, int l, int r, int tl, int tr)
{
    if(tl<=l&&r<=tr) return maxx[u];
    push_down(u,l,r);
    int mid=(l+r)>>1;
    if(tr<=mid) return Query(lz,tl,tr);
    else if(tl>mid) return Query(rz,tl,tr);
    else
    {
        int t1=Query(lz,tl,mid);
        int t2=Query(rz,mid+1,tr);
        return max(t1,t2);
    }
}

int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        for(int i=1; i<=n; i++) scanf("%d",a+i);
        build(1,1,n);
        for(int i=1; i<=m; i++)
        {
            char ch[10];
            int x, y;
            scanf("%s",ch);
            if(strcmp(ch,"Add")==0)
            {
                scanf("%d%d",&x,&y);
                x++, y++;
                Update(1,1,n,x,y,1,1);
            }
            else if(strcmp(ch,"Change")==0)
            {
                scanf("%d%d",&x,&y);
                x++;
                Update(1,1,n,x,x,y,2);
            }
            else if(strcmp(ch,"Ask")==0)
            {
                scanf("%d",&x);
                x++;
                printf("%d\n",Query(1,1,n,x,x));
            }
            else
            {
                scanf("%d%d",&x,&y);
                x++,y++;
                printf("%d\n",Query(1,1,n,x,y));
            }
        }
    }
    return 0;
}

拯救之路

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 14   Accepted Submission(s) : 0

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

在忍者的世界裏有衆多的忍者村,鳴人和佐助出生在木葉村,他們從小一起學習忍術,但是佐助爲了獲得更強的力量離開了木葉村投奔了邪惡的大蛇丸。鳴人爲了不讓佐助被邪惡的力量所控制,決定隻身前往大蛇丸的根據地拯救他。這裏有n個忍者根據地,木葉村位於根據地1,大蛇丸位於根據地n,然後有m條雙向的道路連接這n個根據地,每條路有一個特定的長度L。因爲大蛇丸忍術高深,所以拯救之路註定不安逸。大蛇丸對每條路都施了一種忍術,每條路都用一個特定的字符標註(‘F’,‘U’,‘C’,‘K’中的一種),因此每條路鳴人只能按照特定的路線走方可到達大蛇丸的巢穴拯救佐助,鳴人走的路線必須是按照以下序列 ‘F’->’U’->’C’->’K’->’F’->’U’->’C’->’K’->.... etc,否則他是達到不了大蛇丸的巢穴的。爲了讓拯救之路更艱難,大蛇丸又施加了一種忍術,到達大蛇丸根據地時必須是走的完整的一個或者多個“FUCK”序列,這樣才能拯救成功。
Note:爲了讓拯救行動更加容易,應該讓拯救路線儘量短,同時應該讓“FUCK”序列儘量長。

Input

  第一行輸入一個整數T(1<=T<=500),表示測試數據的組數。
  每組測試數據有兩個整數n(1<=n<=1500),m(1<=m<=20000),表示n個忍者根據地和m條道路。
  接下來輸入m行,每行有4個變量 “u v L c”,表示這是一條路介於根據地u,v(1<=u,v<=n),這條路的長度是L(1<=L<=1000000),c是一個標記字符(‘F’,‘U’,‘C’,‘K’中的一種)。

Output

如果拯救行動無法完成,請輸出Impossible。否則輸出拯救路線的長度以及走過的“FUCK”序列個數。

Sample Input

2 
4 4 
1 2 1 F 
2 1 1 U 
1 3 1 C 
3 4 1 K 
4 4 
1 2 1 F 
2 3 1 U
3 4 1 C 
4 1 1 K

Sample Output

4 1
Impossible

Author

Mr.Ant

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long lld;
const int mn=3333;
const int mm=44444;
const lld oo=1e15;
int  reach[mm], next[mm], flow[mm], ch[mm];
lld  head[mn], que[mn], dis[mn][4], cnt[mn][4], inque[mn];
int n, edge;

void addedge(int u, int v, int c1, int c2,  char c)
{
    ch[edge]=c, reach[edge]=v, flow[edge]=c1, next[edge]=head[u], head[u]=edge++;
    ch[edge]=c, reach[edge]=u, flow[edge]=c2, next[edge]=head[v], head[v]=edge++;
}

int find(char c)
{
   if(c=='F') return 0;
   else if(c=='U') return 1;
   else if(c=='C') return 2;
   else return 3;
}

bool spfa()
{
    int l=0, h=0;
    memset(inque,0,sizeof(inque));
    for(int i=1; i<=n; i++)
        for(int j=0; j<4; j++) dis[i][j]=oo, cnt[i][j]=0;
    inque[1]=1;
    dis[1][0]=0;
    que[l++]=1;
    while(l!=h)
    {
        int u=que[h++];
        if(h==mn) h=0;
        inque[u]=0;
        for(int i=head[u]; i>=0; i=next[i])
        {
            int s=find(ch[i]), v=reach[i], val=flow[i];
            if(dis[v][(s+1)%4]>=dis[u][s]+val)
            {
                if(dis[v][(s+1)%4]==dis[u][s]+val)
                {
                    if(cnt[u][s]+1>cnt[v][(s+1)%4]) cnt[v][(s+1)%4]=cnt[u][s]+1;
                    else continue;
                }
                else
                {
                    dis[v][(s+1)%4]=dis[u][s]+val;
                    cnt[v][(s+1)%4]=cnt[u][s]+1;
                }
                if(!inque[v])
                {
                    inque[v]=1;
                    que[l++]=v;
                    if(l==mn) l=0;
                }
            }
        }
    }
    if(dis[n][0]==oo||!cnt[n][0]) return false;
    else return true;
}

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int m, T, tcase=0;
    cin >> T;
    while(T--)
    {
        cin >> n >> m;
        edge=0;
        memset(head,-1,sizeof(head));
        int mp[4]={0,0,0,0}, ct=0;
        while(m--)
        {
            int u, v, val, se;
            char sh[3];
            scanf("%d%d%d%s",&u,&v,&val,sh);
            addedge(u,v,val,val,sh[0]);
            if(n==1&&u==1&&v==1)
            {
                se=find(sh[0]);
                if(!mp[se]) ct++, mp[se]=val;
                else mp[se]=min(mp[se],val);
            }
        }
        if(ct==4)
        {
           lld sum=mp[0]+mp[1]+mp[2]+mp[3];
           printf("%I64d %d\n",sum,ct/4);
           continue;
        }
        bool ok=spfa();
        if(!ok) puts("Impossible");
        else printf("%I64d %I64d\n",dis[n][0],cnt[n][0]/4);
    }
    return 0;
}

ZEROm的乘法運算

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 24   Accepted Submission(s) : 1

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

ZEROm要too_weak快速計算下列程序的運算結果Sum,too_weak必然是不會的,現在請你幫助他.
int Sum=0;
for(int i=1;i<=N;i++)
  for(int j=i+1;j<=N;j++)
   for(int k=j+1;k<=N;k++)
   Sum+=a[i]*a[j]*a[k];

Input

輸入數據有很多組,以EOF結尾。(大規模輸入。請用scanf)
每組數據的第一行包含一個正整數N(1 <= N<= 1000000),說明第二行有N個數。
第二行有N個數,分別代表a[1],a[2],a[3]....a[N].(0<=a[i]<=10^9)

Output

因爲Sum可能很大,輸出Sum對9973求餘的結果。

Sample Input

5
1 2 3 4 5

Sample Output

225

Author

moonlike

容斥原理的簡單應用。

#include <cstdio>
using namespace std;
typedef long long LL;
const int mod = 9973;
const int maxn =1000000+5;
LL a[maxn];
int main()
{
    int n;
    while(~scanf("%d",&n)){
        LL sum=0,xxx=0;
        for(int i=0;i<n;i++){
            scanf("%I64d",&a[i]);
            sum=(sum+a[i])%mod;
            xxx=xxx+a[i]*a[i]%mod*a[i]%mod;
        }
        for(int i=0;i<n;i++)
            xxx=(xxx+3*a[i]*a[i]%mod*(sum-a[i])%mod)%mod;
        sum=sum*sum%mod*sum%mod;
        sum=((sum-xxx)%mod+mod)%mod;
        printf("%I64d\n",sum*8311%mod);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章