The 2018 ACM-ICPC China JiangSu (2018徐州邀請賽)(solve9/11)

題目鏈接:https://www.jisuanke.com/contest/1408?view=challenges

A題:

題意:就是給你n*m的格子,然後k個點,K個點有火,開始四個方向蔓延,問你最後燒的那個格子的位置,有多個的話,x優先再y優先。

思想:n*m*t暴力求即可。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int Map[2005][2005];
int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int k,a,b,Max=-1;
		scanf("%d",&k);
		memset(Map,INF,sizeof(Map));
		while(k--)
		{	
			scanf("%d%d",&a,&b);
			for(int i=1;i<=n;i++)
				for(int j=1;j<=m;j++)
					Map[i][j]=min(Map[i][j],abs(a-i)+abs(b-j));
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				Max=max(Max,Map[i][j]);
		
		int flag=1;
		for(int i=1;i<=n && flag;i++)
		{
			for(int j=1;j<=m;j++)
			{
				if(Map[i][j]==Max)
				{
					printf("%d %d\n",i,j);
					flag=0;
					break;
				}
			}
		}	
	}
	return 0;
} 

B題

題意:讓你求n的全排列中逆序對(i<j && a[i] > a[j] )的的個數爲k的方案數。

思想:先打表看看是否有規律。下圖借鑑一個打表的圖,發現有規律。

æ表ç»æ

然後不難發現當j < i 的時候 dp[i][j]等於前邊的dp[i-1][j]等i==j的時候發現d[i][j]=dp[i-1][j]-dp[i-1][j-i]

內存給了64M所以就需要滾動數組了。

#include<bits/stdc++.h>
using namespace std;
const long long mod = 1e9+7;
struct node{
	int n;
	int k;
	int id;
}no[5005];
bool cmp(node a,node b)
{
	return a.n<b.n;
}
long long dp[3][5005];
long long ans[5005];
int main()
{
	int cnt=0;
	int n,k,l=0;
	while(scanf("%d%d",&n,&k)!=EOF)
	{
		no[cnt].n=n;
		no[cnt].k=k;
		no[cnt].id=cnt;
		cnt++;
	}
	sort(no,no+cnt,cmp);
	dp[0][0]=1;
	for(int i=1;i<=5000;i++)
	{
		long long sum=0;
		for(int j=0;j<=5000;j++)
		{
			sum=(sum+dp[i-1&1][j])%mod;
			if(j>=i)
				sum=(sum-dp[i-1&1][j-i]+mod)%mod;
			dp[i&1][j]=sum;
		}
		while(l<cnt && no[l].n==i)
		{
			ans[no[l].id]=dp[i&1][no[l].k];
			l++;
		}
	}
	for(int i=0;i<cnt;i++)
		printf("%lld\n",ans[i]);
	return 0;
} 

D題

題意:題意:給定一個長度爲n的向量(0,0,0..) 每次可以在某個位置加1,求加到最終向量(U1,U2,..,Un)的方案數。

思想: 組合數學問題記SUM=U1+U2..+Un 答案是SUM!/(U1!*U2!...*Un!) 預處理逆元 矩陣快速冪求解即可

E題

題意:求(1,2)到(n-1,m)和(2,1)到(n,m-1)不交叉的路徑數。

思想: Lindstrm–Gessel–Viennotlemma 定理求解即可。 參考下:https://blog.csdn.net/passer__/article/details/81156093

G題

題意:有一個長度爲n的序列,長度爲m的劃窗,計算每次劃窗內的乘積的求和。

思想:分塊,每一塊爲m,對於每一塊都求出來前綴和和後綴和,對於當前區間恰好是這個塊的話,那結果就等於後綴和,

如果不是的話,就等於下一塊的那部分的前綴和*當前塊的後綴和。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
int n, m;
ll a[maxn], X, Y, Z, mod;
ll s[maxn], e[maxn];
int main()
{
    while(scanf("%d%d%lld", &n, &m, &mod) != EOF){
        scanf("%lld%lld%lld%lld", &a[0], &X, &Y, &Z);
        for(int i = 1; i < n; i++)
            a[i] = (X * a[i - 1] % mod * a[i - 1] % mod + Y * a[i - 1] % mod + Z) % mod;
         
        for(int i = 0; i < n; i++)
            if(i % m == 0)
                s[i] = a[i] % mod;
            else
                s[i] = s[i - 1] * a[i] % mod;
        for(int i = n - 1; i >= 0; i--)
            if((i + 1) % m == 0 || i == n - 1)
                e[i] = a[i] % mod;
            else
                e[i] = e[i + 1] * a[i] % mod;
         
        ll ans = 0;
        for(int i = 0; i <= n - m; i++)
            if(i % m == 0)
                ans += e[i];
            else
                ans = ans + (s[i + m - 1] * e[i]) % mod;
         
        printf("%lld\n", ans);
    }
 
    return 0;
}

H題

題意:計算N階線性齊次遞推式第K項。就是給你一個式子,讓你求出來第K項。

思想:官方題解意思是模板·····模板·····衆人所知的模板·····時間複雜度n^2*logk

https://github.com/ICPCCamp/BlackBoxLinearAlgebra  (出題人附送的PPT+代碼)

此題也可以用fft寫,時間複雜度爲nlognlogk,BlackBoxLinearAlgebra算法的時間複雜度爲n^2logk

I題

題意:n天有m見衣服,給你一個好感度爲DP[i][j]爲第今天穿第i件衣服明天穿第j件衣服的好感度,問你如何穿讓好感度最高,輸出好感度即可。

思想:假如考慮只有2天的話,是不是隻需要兩層for循環求一下最大值即可,三天的話三層,四天四層,因此發揮想象這就是一個n-1層for循環的一個式子,DP[i][j]這個矩陣的每個元素每次都取最大值。最後就變成第一天穿i這件衣服,最後一天穿j這件衣服的好感度的最大值。(沒懂可以自己畫畫),這樣就可以用矩陣快速冪來優化求解。

時間複雜度m^3logn

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct matrix{
    int row,col;
    ll A[105][105];
    matrix(int Row=0,int Col=0){  
        memset(A,0,sizeof(A));  
        row=Row;col=Col;  
    }  
};  
 
matrix operator *(matrix a,matrix b){  
    matrix c(a.row,b.col);  
    for(int i=0;i<a.row;i++)  
        for(int j=0;j<b.col;j++)  
            for(int k=0;k<a.col;k++)  
                c.A[i][j]=max(c.A[i][j],a.A[i][k]+b.A[k][j]);  
    return c;  
}  
matrix matrix_pow(matrix a,ll n){  
    matrix ans(a.row,a.col);  
    for(int i=0;i<a.row;i++)  
            ans.A[i][i]=0;  
    while(n){  
        if(n%2)  
            ans=a*ans;  
        a=a*a;  
        n/=2;  
    }  
    return ans;  
}  
int main()
{
    ll k;
    int m;
    while(scanf("%lld%d",&k,&m)!=EOF)
    {
        matrix temp(m,m);
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                scanf("%lld",&temp.A[i][j]);
        temp=matrix_pow(temp,k-1);
        ll ans=0;
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                ans=max(ans,temp.A[i][j]);
        printf("%lld\n",ans);
    }
    return 0;
} 

J題

題意:計算Meo set個數

思想:Meo set定義是1-n的子集中任何2個數的差值大於1,然後求集合元素內乘積的平方和。打表找規律。

結果是(n+1)!-1,java寫一下就行。

K題

題意:給你一個n*n的矩陣代表是第i個城市到達每個城市都有一條路並且距離是a[i][j]在前提a[i][j]不等於0,如果等於0就說明沒有路。問在不影響0到任何點的情況下刪除最多的邊,有多少種不同的方案。

思想:考慮只留下一個最小生成樹即可,其餘的邊都刪除,對於某點有多條路,那就刪除C(n,n-1)條路,等價於刪除C(n,1)。所以最後的結果就是所有點的度的一個乘積。

#include<bits/stdc++.h>
using namespace std;
long long mod = 1000000007;
long long Count[105];
int Map[105][105];
char str[105][105];
int head[105];
int dist[105];
int vis[105];
struct node{
    int v;
    int valu;
    int next;
}no[100*100*2];
int cnt,n;
void add(int u,int v,int valu)
{
    no[cnt].v=v;
    no[cnt].valu=valu;
    no[cnt].next=head[u];
    head[u]=cnt++;
}
void spfa(int u)
{
    for(int i=0;i<=n;i++)
    {
        vis[i]=0;
        dist[i]=1<<29;
    }
    vis[u]=1;
    dist[u]=0;
    queue<int>q;
    q.push(u);
    while(!q.empty())
    {
        int U=q.front();
        q.pop();
        vis[U]=0;
        for(int i=head[U];i!=-1;i=no[i].next)
        {
            int v=no[i].v;
            if(dist[v]>dist[U]+no[i].valu)
            {
                dist[v]=dist[U]+no[i].valu;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
void diu(int u)
{
    memset(Count,0,sizeof(Count));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(Map[i][j]==0)    
                continue;
            if(dist[j] == dist[i]+Map[i][j])
                Count[j]++;
        }
    } 
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)
            scanf("%s",str[i]+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                Map[i][j]=str[i][j]-'0';
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(Map[i][j]!=0)
                    add(i,j,Map[i][j]);
        spfa(1);
        diu(1);
        long long ans=1;
        for(int i=2;i<=n;i++)
            ans=(ans*Count[i])%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

 

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