很久沒做程序設計題目了,狀態下滑的有些厲害。
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;
}
歡迎評論!