CodeForces Round 630(div2)部分題解

很久沒做程序設計題目了,狀態下滑的有些厲害。

A.Exercising Walk
原題鏈接:
http://codeforces.com/contest/1332/problem/A
題意:
一個人處在一個給出的區間內,這個人可以向上下左右四個方向走。然後給出了這個人在每個方向上走的步數:(a,b,c,d)對應着(上,下,左,右)。問這個小人會不會走出給定的區域。
題解:
很明顯,左右方向和上下方向分開考慮,互不影響。每個方向的步數可以相互抵消。比如左走一步,右走一步就回到原點。
注意:如果最終抵消爲0且該方向上步數不是爲0,也依然要判斷在某個方向上是不是至少有1的長度,因爲在抵消的過程中,小人一定是會動的,所以必須給他空間才能動。
AC代碼:

#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//author wjl

using namespace std;

int a,b,c,d;
int x,x1,x2;
int f,f1,f2;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>a>>b>>c>>d;
		cin>>x>>f>>x1>>f1>>x2>>f2;
		bool ok1=false;
		if(a>b)
		{
			int d1=a-b;
			int d2=x-x1;
			if(d2>=d1)
				ok1=true;
			if(max(a,b)>0&&(x2-x1)==0)
			{
				ok1=false;
			}
		}
		else
		{
			int d1=b-a;
			int d2=x2-x;
			if(d2>=d1)
				ok1=true;
			if(max(a,b)>0&&(x2-x1)==0)
			{
				ok1=false;
			}
		}
		bool ok2=false;
		if(c>d)
		{
			int d1=c-d;
			int d2=f-f1;
			if(d2>=d1)
				ok2=true;
			if(max(c,d)>0&&(f2-f1)==0)
			{
				ok2=false;
			}
		}
		else
		{
			int d1=d-c;
			int d2=f2-f;
			if(d2>=d1)
				ok2=true;
			if(max(c,d)>0&&(f2-f1)==0)
			{
				ok2=false;
			}
		}
		//cout<<ok1<<ok2<<endl;
		//DBEUG(ok2);
		if(ok1&&ok2)
			cout<<"Yes\n";
		else
			cout<<"No\n";
	}
	return 0;
}

B.Composite Coloring
原題鏈接:
http://codeforces.com/contest/1332/problem/B
題意:
給你一個數組,數組中每個元素小於1000且都是複數。
現在你有11種顏色,你可以從其中挑選m種顏色(m>=1&&m<=11)去給每個元素進行塗色。要求塗同一種顏色的所有元素兩兩之間的最小公因數大於1.給出合理的方案。
題解:
數組元素小於1000,可給的顏色又有11種,而平方小於1000的質數有11個。很容易就想到以每一個質數塗色依據,將數組中的元素按照最小非1的因數去歸類。然後按照每一類去統一塗色即可。
爲什麼平方小於1000就可以?
因爲A>B方,A的最小非1因數纔有可能是比B大的。
AC代碼:

#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//author wjl

using namespace std;
#define LL long long

const int maxn=1e3+5;
int a[10005];
int n;
int prime[11]={2,3,5,7,11,13,17,19,23,29,31};
int ans[1005];
int out[1005];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		MS0(ans);
		bool vis[1005];
		MSf(vis);
		int cnt=1;
		for(int i=0;i<n;i++)
		{
			cin>>a[i];
			for(int j=0;j<11;j++)
			{
				if(a[i]%prime[j]==0)
				{
					if(!vis[prime[j]])
						cnt++;
					vis[prime[j]]=true;
					break;
				}
			}
		}
		int tmp=1;
		for(int j=0;j<11;j++)
		{
			if(vis[prime[j]])
			{
				ans[prime[j]]=tmp++;
			}
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<11;j++)
			{
				if(vis[prime[j]])
				{
					if(a[i]%prime[j]==0)
					{
						out[i]=ans[prime[j]];
						break;
					}
				}
			}
		}
		cout<<cnt-1<<"\n";
		for(int i=0;i<n;i++)
		{
			cout<<out[i]<<" ";
		}
		cout<<"\n";
	}
	return 0;
}

C.K-Complete Word
原題鏈接:
http://codeforces.com/contest/1332/problem/C
題意:
給你一個字符串,想讓他變成一個迴文串(s[i]=s[n+1-i]),且具有周期K(s[i]=s[i+k])。你每次操作可以改變字符串中某個字符,問最少改變多少次。
題解:
由迴文串和週期可以推出s[n-k+i]=s[n+1-i],可以發現每一個週期內也是迴文串。之後遍歷一個週期內s[i] (i>=1&&i<=k) 以其他週期內對應同位置的字符 分別爲26個拉丁字母需要改變多少次即可。
AC代碼:

#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//author wjl

using namespace std;
#define LL long long

const int maxn=2e5+5;

int num[maxn][30];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		int n,k;
		string s;
		cin>>n>>k;
		cin>>s;
		for(int i=1;i<=k;i++)
		{
			for(int j=0;j<26;j++)
				num[i][j]=0;
			for(int j=0;j<n/k;j++)
			{
				int now=i+j*k-1;
				int tmp=s[now]-'a';
				num[i][tmp]++;//記錄每個位置每一個字符出現的次數
			}
		}
		int ans=0;
		for(int i=1;i<=(k+1)/2;i++)
		{
			int msum=5*maxn;
			for(int j=0;j<26;j++)
			{
				if(k-i+1==i)//奇迴文串
				{
					if(msum>(n/k-num[i][j]))
					{
						msum=n/k-num[i][j];
					}
				}
				else if(msum>(2*n/k-num[i][j]-num[k-i+1][j]))
				{
					msum=2*n/k-num[i][j]-num[k-i+1][j];
				}
			}
			ans+=msum;
		}
		cout<<ans<<"\n";
	}
	return 0;
}

D.Walk on Matrix
原題鏈接:
http://codeforces.com/contest/1332/problem/D
題意:
給出一個n*m矩陣(矩陣上的每個元素有自己的value),一個人初始處於(0,0),要走到(n,m),只能向右和向下走,請找到最長的路。最長的路是這樣定義的:路徑上所有的值按位與的值。
小明用了一種錯誤的dp方法,求解出來了答案x。而正確答案爲m。現在已知m和x的差值k。請構造出一個矩陣使得小明算出來的答案與正確答案相差剛好爲k。
題解:
小明錯誤以爲局部最優解可以推向全局最優解。
通過樣例可以發現,只需要構造兩條路,一條正確的路,一條錯誤的路。在正確的路徑上通過矩陣上的其他值去影響局部最優,誘導小明走錯誤的路即可。
例如以下2*3的矩陣:

217^k 217 0
k 217^k k

正確的路 :(0,0)->(0,1)->(1,1)->(1,2)
錯誤的路:(0,0)->(0,1)->(0,2)->(1,2)
你只需要構造無論怎麼走小明按照錯誤的局優得到的結果都是0,同時又存在一條結果爲k的最優路徑即可。
給出一個表格

a b a^b (a^b)&b (a^b)&b&(a^b)
0 0 0 0 0
0 1 1 1 1
1 0 1 0 0
1 1 0 0 0

令a=217 b=k 就能夠得到(0,0)->(1,0)-(1,1)的結果,發現這個結果取決於b(即k)。

a b a^b (a^b)&a (a^b)&a&(a^b)
0 0 0 0 0
0 1 1 0 0
1 0 1 1 1
1 1 0 0 0

令a=217 b=k 就能夠得到(0,0)->(0,1)-(1,1)的結果,發現這個結果取決於a(即217)。
已知k<1e5<217,所以肯定走(0,0)->(1,0)->(1,1)時dp[1][1]爲k,走(0,0)->(1,0)->(1,1)的dp[1][1]爲2^17 。小明在選擇的時候肯定會選擇較大的217。然而217 & k的結果必然是0。至此,小明已經走上了不歸路。
實際上最優路徑是dp[1][1]dn等於k的路。最終最優路徑的結果爲k&k=k。
AC代碼:

#include <bits/stdc++.h>
//#pragma GCC optimize(2)
//author wjl

using namespace std;
#define LL long long
#define Rint register int
#define U unsigned
#define forn(i,a,b) for(int i = a;i <= b;++i)
#define nfor(i,a,b) for(int i = a;i >= b;--i)
#define pii pair<int ,int>
#define MS0(X) memset(X,0,sizeof(X))
#define MSf(X) memset(X,false,sizeof(X))
#define MS1(X) memset(X,-1,sizeof(X))
#define BR printf("--------------------\n")
#define pb push_back
#define rep(i,a,b) for(Rint i=a;i<=b;++i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const double PI=atan(1.)*4.;
const int maxn=1e6+5;
const int inf = 0x3f3f3f3f;
const int mod=1e9+7;
const double e=2.71828182845904523536;
int dirx[8]={1,0,-1,0,1,-1,-1,1};
int diry[8]={0,1,0,-1,1,1,-1,-1};

int n,m;
int a[1005][1002];
int dp[1005][1005];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    /*
    //小明錯誤的dp
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    dp[1][1]=a[1][1];
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            //dp[i+1][j]=max(dp[i+1][j],dp[i][j]&a[i+1][j]);
            //dp[i][j+1]=max(dp[i][j+1],dp[i][j]&a[i][j+1]);
            dp[i][j]=max(dp[i][j],max(dp[i-1][j]&a[i][j],dp[i][j-1]&a[i][j]));
            cout<<dp[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<dp[n][m];*/
    int k;
    cin>>k;
    int mx=(1<<17);
    cout<<2<<" "<<3<<"\n";
    int ans[2][3];
    ans[0][0]=mx^k;
    ans[0][1]=mx;
    ans[0][2]=0;
    ans[1][0]=k;
    ans[1][1]=mx^k;
    ans[1][2]=k;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
        {
            cout<<ans[i][j]<<" "; 
        }
        cout<<"\n";
    }
    return 0;
}

歡迎評論!

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