很久没做程序设计题目了,状态下滑的有些厉害。
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;
}
欢迎评论!