A. Palindromic Twist
题意:每个字母都会变成它的ASCII值+1或者-1的情况(不可能不变化),问有没有一种可能的变化使得最后的串为回文串?
思路:从中间向两边遍历+判断
#include
#include
#include
#include
#include
#define memset(a,v) memset(a,v,sizeof(a))
using namespace std;
const int MAXL(3*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
string str;
bool judge(int i,int j)
{
if(str[i]-1==str[j]-1)
return true;
if(str[i]-1==str[j]+1)
return true;
if(str[i]+1==str[j]-1)
return true;
if(str[i]+1==str[j]+1)
return true;
return false;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
cin>>str;
int flag=0;
for(int i=n/2,j=n/2-1;i
B. Numbers on the Chessboard
题意:有一个n*n大小的方格,里面有n^2个数字,数字是按照这样的规则安防的:从1开始,下标从(1,1)开始。当下标的和为偶数的时候从左向右吗,从上到校按序依次放置数字,然后放置下标和为奇数的方格。给出q个询问,问下标为(x,y)的方格的数字是多少?
思路:直接找规律就好,我写的代码可能会有点冗杂。
n分奇偶的情况。
1.当n为偶数时:
①下标和为偶数时:因为数字是按照顺序依次递增的,所以我们先统计出第1到x-1行有多少个数字,然后再加上第x行有多少个数字,最后相加即可。
②下标和为奇数时:①得出的答案+n*n / 2
2.当n为奇数时:
这个情况稍微复杂些.
因为每两行的数字会差了一个,所以我们把两行看成一行去计算,然后按照上面的方法找出和。
#include
#include
#include
#include
#include
#define memset(a,v) memset(a,v,sizeof(a))
using namespace std;
const int MAXL(3*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int main()
{
LL n,q;
cin>>n>>q;
while(q--)
{
LL x,y;
cin>>x>>y;
if( !(n&1) )//n为偶数
{
if((x+y)&1)//下标和为奇数的情况
{
LL temp=n/2;
LL sum=temp*(x-1); //这个是统计每行上面有多少个数字
if(y&1)
y=(y+1)/2;
else
y/=2; //if else 统计当前行有多少个数字
cout<
C. Minimum Value Rectangle
题意:给出n个数字,n>=4。从这里面选出4个组成一个长方形,使得周长的平方/面积 最小。
输入保证答案存在。
思路:假设选出来的长为 L,高位H。那么周长的平方C^2=4*(L+H)^2,面积S=LH。
4为常数,不影响最终结果,扔掉~
那么C^2/S 可以最后化简为 L/H + H/L 的形式。
由上式可知,当L==H的时候,答案最小。
如果没有L==H的情况,那么我们就把所有可能组成的边比较,找出最小的答案。
#include
#include
#include
#include
#include
#define memset(a,v) memset(a,v,sizeof(a))
#define eps 1.0E-8
using namespace std;
const int MAXL(1e4);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int haxi[MAXL+50];
int a[1000000+50];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
memset(haxi,0);
int len=0;
int flag=0;
int temp=0,ans1=0,ans2=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
haxi[x]++;
if(haxi[x]==2)
a[len++]=x;
if(haxi[x]==4)//正方形的情况,直接得到答案
{
flag=1;
ans1=ans2=x;
}
}
if(!flag)
{
double mi=INF;
sort(a,a+len);
for(int i=1;i
D. Mouse Hunt
题意:有n个房间,一只老鼠,现在我们要抓住这只老鼠,于是我们要在房间里设置老鼠夹。可是我们想用最少的花费并同时保证一定可以抓住老鼠。
所以输入的第一行为在每个房间里设置老鼠夹所需要的花费。
老鼠如何行动呢?它可能会从任意一个房间里出来,并且可能会跑到任何一个房间。
所以输入的第二行为在第 i 个房间时,这只老鼠会跑到第a[i]个房间。
PS:如果 i==a[i] ,那么老鼠这时候就不跑了。
思路:一开始可能会想到并查集,但是我写的并查集没有A掉...可能是因为在设置祖先的时候情况分的不对。
后来把输入的第二行画成一个图时,思路就变的开始清晰起来。
①首先老鼠在每个房间一定会跑到下一个房间,只有当 i==a[i]时,才终止跑路。
所以我们必须要在这样的房间内设置一个老鼠夹,不管他从哪个房间来,一定会在这里抓住。
②但是还是有别的情况,比如老鼠从2跑到房间3,3又跑到房间2,形成了一个环。
这时候我们就需要在这个环里面的所有房间,找一个花费最小的房间设置老鼠夹。
一定会有环吗?
一定会有环。
因为老鼠每次都要跑到下一个房间,所以一定会再次跑回之前跑过的房间。
有一种情况:
从1->2>3>4->5,
最后5的a[5]为5,也可以看做5这个点为一个环。
算法:输入的时候把①的情况先处理掉,然后对剩下的图拓扑排序,把入度为0的点处理掉,最后剩下一个环,在环里找最小的花费即可。
#include
#include
#include
#include
#include
#include
#define memset(a,v) memset(a,v,sizeof(a))
#define eps 1.0E-8
using namespace std;
const int MAXL(2*1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
typedef long long int LL;
int a[MAXL+50];
int c[MAXL+50];
int indegree[MAXL+50];
int vis[MAXL+50];
int n;
LL ans=0;
void toposort()
{
queueq;
for(int i=1;i<=n;i++)
if(!vis[i] && !indegree[i]) q.push(i),vis[i]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
indegree[a[u]]--;
vis[u]=1;
if(!indegree[a[u]]&&!vis[a[u]])
q.push(a[u]);
}
}
void solve()
{
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
int u=i,v=a[u];
vis[u]=vis[v]=1;
int temp=c[u];
while(u!=v)
{
temp=min(temp,c[v]);
v=a[v];
vis[v]=1;
}
ans+=temp;
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",c+i);
for(int i=1; i<=n; i++)
{
scanf("%d",a+i);
if(a[i]==i)
ans+=c[i],vis[i]=1;
else
indegree[a[i]]++;
}
toposort();
solve();
cout<