给定三个数 n , m , x n,m,x n,m,x ,定义一个 3 ∗ 5 3*5 3∗5 的矩阵的纵向排列为 1 4 7 10 13 2 5 8 11 14 3 6 9 12 15 \begin{matrix} 1 & 4 & 7 & 10 & 13 \\ 2 & 5 & 8 & 11 & 14 \\ 3 & 6 & 9 & 12 & 15 \\ \end{matrix} 123456789101112131415 ,其横向排列是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \begin{matrix} 1 & 2 & 3 & 4 & 5 \\ 6 & 7 & 8 & 9 & 10 \\ 11 & 12 & 13 & 14 & 15 \\ \end{matrix} 161127123813491451015 ,求纵向排列 x x x 的位置在其横向排列矩阵中的对应数字是多少 ?
借鉴计算机中二维数组从0开始的表示方法,将原来从1开始的数组映射到从0开始,统一将 X − − , X--, X−−,有 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14 \begin{matrix} 0 & 3 & 6 & 9 & 12 \\ 1 & 4 & 7 & 10 & 13 \\ 2 & 5 & 8 & 11 & 14 \\ \end{matrix} 01234567891011121314 观察有 x 的 横 纵 坐 标 为 ( x % n , x / n ) , 坐 标 为 ( x , y ) 的 点 在 横 向 排 列 之 后 的 数 字 为 x ∗ m + y x的横纵坐标为(x \%n,x/n) ,坐标为(x,y)的点在横向排列之后的数字为x*m+y x的横纵坐标为(x%n,x/n),坐标为(x,y)的点在横向排列之后的数字为x∗m+y 。
// Problem: A. Strange Table
// Contest: Codeforces - Codeforces Round #710 (Div. 3)
// URL: https://codeforces.com/contest/1506/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int n,m,_;
int main()
{
cin>>_;
while(_--)
{
cin>>n>>m>>x;
x--;
ll x1,y1;
x1=x%n,y1=x/n;
cout<<x1*m+y1+1<<endl;
}
return 0;
}
如果不将下标进行映射就会陷入特判中,超级麻烦
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef long long ll;
const int N=110;
int n;
/*
1 3
2 4
*/
int main()
{
int t;cin>>t;
while(t--)
{
long long n,m,x;scanf("%lld%lld%lld",&n,&m,&x);
int X,Y;
if(x%n==0)
X=x/n;
else
X=x/n+1;
Y=x-x/n*n;
if(Y==0)
Y=n;
// Y,X
// cout<<"Y="<if (X==m)
cout<<Y*m<<endl;
else
cout<<(Y-1)*m+X<<endl;
// cout<
}
}
和这题类似的一道题
给定 w , m , n , w 是 宽 度 , m 和 n 是 两 个 编 号 , 求 两 个 编 号 之 间 的 曼 哈 顿 距 离 w,m,n,w是宽度,m和n是两个编号,求两个编号之间的曼哈顿距离 w,m,n,w是宽度,m和n是两个编号,求两个编号之间的曼哈顿距离 曼哈顿距离的定义:给定两个坐标 ( x 1 , y 1 ) , ( x 2 , y 2 ) , d i s = a b s ( x 1 − x 2 ) + a b s ( y 1 − y 2 ) (x1,y1),(x2,y2),dis=abs(x1-x2)+abs(y1-y2) (x1,y1),(x2,y2),dis=abs(x1−x2)+abs(y1−y2)
1 2 3 4 5 6
12 11 10 9 8 7
13 14 15 .....
input
6 8 2
ouput
4
同样将所有下标左移
0 1 2 3 4 5
11 10 9 8 7 6
12 13 14 15 16 17
观察有对于移动后的 x , 它 的 下 标 是 ( x / w , x % w ) , 当 x / w 是 奇 数 的 时 候 , x 的 纵 坐 标 = w − 1 − x % w , 直 接 计 算 即 可 x,它的下标是(x/w,x\%w) ,当x/w是奇数的时候,x的纵坐标=w-1-x\%w,直接计算即可 x,它的下标是(x/w,x%w),当x/w是奇数的时候,x的纵坐标=w−1−x%w,直接计算即可
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int w,n,m,_;
int main()
{
cin>>w>>n>>m;
int x1,y1,x2,y2;
n--,m--;
//借鉴c++中二维数组的存储方式,tql
if((n/w)%2==0)
x1=n/w,y1=n%w;
else
x1=n/w,y1=w-1-n%w;
if((m/w)%2==0)
x2=m/w,y2=m%w;
else
x2=m/w,y2=w-1-m%w;
cout<<abs(x1-x2)+abs(y1-y2)<<endl;
return 0;
}
给你一个由 .
和*
组成长为 n n n的字符串和数字 k k k,你需要把串中第一个*
和最后一个*
替换成字符x
,并且两个相邻的字符x
之间的距离不能超过 k k k ,如果你要替换 i , j 这 两 个 字 符 , 距 离 定 义 为 j − i i,j这两个字符,距离定义为j-i i,j这两个字符,距离定义为j−i
询问想要达到上述目的的最小替换次数是多少
(题目保证有解)
首先找到第一个*
和最后一个*
的位置,特判只有一个*
的情况,之后以 k 为 间 隔 k为间隔 k为间隔 贪心向后查找,最后判断贪心过程中最后一个查到到*
的位置是不是一开始的 l a s t last last如果是的话直接输出,否则答案+1再输出
一开始贪心也不对,这题得知道首次出现和最后一次出现的位置,贪心的时候得在第二个for循环里计数,不然很容易错。
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef long long ll;
const int N=110;
int n;
int main()
{
int k,t,n;cin>>t;
while(t--)
{
string s;cin>>n>>k>>s;
int cnt=1,fir=-1,last=-1;
/*
特判只有一个*的
然后把首填好
之后在这个区间里尽可能的向后找,直到把尾巴填上
*/
for(int i=0;i<n;i++)
if(s[i]=='*')
{
fir=i;break;}
for(int i=n-1;i>=0;i--)
if(s[i]=='*')
{
last=i;break;}
if(fir==last)
{
cout<<1<<endl;
continue;
}
int pos=fir;
int i;
for(i=fir;i+k<=last;)
{
for(int j=i+k;j>i;j--)
{
if(s[j]=='*')
{
cnt++;
pos=j;break;
}
}
i=pos;
}
if(i==last)
cout<<cnt<<endl;
else
cout<<cnt+1<<endl;
}
}
给两个字符串 a , b a,b a,b (不一定等长),每次操作可以删除 a , b a,b a,b 串的第一个或最后一个字符,空串是相等的,问最少进行 多少次操作可以使得 a , b a,b a,b 两个字符串相等
I n p u t Input Input
The first line contains a single integer t ( 1 ≤ t ≤ 100 ) t\ (1 \le t \le 100) t (1≤t≤100). Then tt test cases follow.
The first line of each test case contains the string a ( 1 ≤ ∣ a ∣ ≤ 20 ) a\ (1 \le |a| \le 20) a (1≤∣a∣≤20), consisting of lowercase Latin letters.
The second line of each test case contains the string b ( 1 ≤ ∣ b ∣ ≤ 20 ) b\ (1 \le |b| \le 20) b (1≤∣b∣≤20), consisting of lowercase Latin letters.
O u t p u t Output Output
For each test case, output the minimum number of operations that can make the strings aa and bb equal.
a n s = a . s i z e ( ) + b . s i z e ( ) − 2 ∗ 两 者 最 长 公 共 子 串 的 长 度 ans=a.size()+b.size()-2*两者最长公共子串的长度 ans=a.size()+b.size()−2∗两者最长公共子串的长度
O ( n 3 ∗ 20 ) , 类 似 区 间 d p 再 乘 上 配 对 的 时 间 复 杂 度 O(n^3*20),类似区间dp再乘上配对的时间复杂度 O(n3∗20),类似区间dp再乘上配对的时间复杂度
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef long long ll;
const int N=1101;
int n;
/*
对于两个长度不超过20的字符串找到他们的连续最长公共子串的长度
*/
int main()
{
int t;cin>>t;
while(t--)
{
string s,ss;
cin>>s>>ss;
int res=0;
int len=min(s.size(),ss.size());
// debug(len);
for(int i=1;i<=len;i++)//枚举公共的串长
{
// int t=0;
// debug(i);
for(int j=0;j+i-1<s.size();j++)//枚举起点
for(int k=0;k+i-1<ss.size();k++)//枚举起点
{
if(s.substr(j,i)==ss.substr(k,i))
{
res=max(res,i);
}
}
}
// debug(res);
// debug(s.size()+ss.size());
cout<<s.size()+ss.size()-2*res<<endl;
}
}
给你一个数组,可以进行一下操作 0 或 者 多 次 0或者多次 0或者多次 ,挑选数组中两个不同的元素,将他们删除。
问,进行上述操作后所得到数组可能的最小的大小是?
使用优先队列,下面是合并果子的AC代码
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int n,m,_,x;
int main()
{
cin>>n;
priority_queue<int,vector<int>,greater<int>>que;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
que.push(x);
}
int res=0;
while(que.size()>1)
{
int a=que.top();
que.pop();
int b=que.top();
que.pop();
res+=a+b;
que.push(a+b);
}
cout<<res;
return 0;
}
顺便小结一下priority_queue的使用方法
priority_queueque,默认大根堆
priority_queue,greater>que,小根堆
size()
empty()
push()//压入一个元素
top()//返回堆顶元素
pop()弹出堆顶元素
遍历方式,不用for(auto c:que)的方式进行遍历,不能使用迭代器遍历
可以用while(que.size())
{
cout<
本题代码
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int n,m,_,x;
int main()
{
cin>>_;
while(_--)
{
scanf("%d",&n);
map<int,int>mp;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
mp[x]++;
}
priority_queue<int>que;//使用大根堆
for(auto c:mp)
que.push(c.second);
while(que.size()>1)
{
int a=que.top();
que.pop();
int b=que.top();
que.pop();
a--,b--;
if(a)
que.push(a);
if(b)
que.push(b);
}
if(que.empty())puts("0");
else
printf("%d\n",que.top());
}
return 0;
}
$ res= max(1,num-(n-num))$ ,看除了众数之外的其他数出现的次数,如果其他数出现的次数大于众数,$ res=0 否则 res= num-(n-num)$
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int n,m,_,x;
int main()
{
cin>>_;
while(_--)
{
scanf("%d",&n);
map<int,int>mp;
int cnt=-1;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
mp[x]++;
cnt=max(cnt,mp[x]);
}
if(n&1)
printf("%d\n",max(1,cnt-(n-cnt)));
else
printf("%d\n",max(0,cnt-(n-cnt)));
}
return 0;
}
给一个排列 P P P 对应的一个前缀最大值的序列 q q q,如 p = [ 3 , 2 , 4 , 1 , 7 , 5 , 6 ] − > q = [ 3 , 3 , 4 , 4 , 7 , 7 , 7 ] p=[3, 2, 4, 1, 7, 5, 6]->q=[3, 3, 4, 4, 7, 7, 7] p=[3,2,4,1,7,5,6]−>q=[3,3,4,4,7,7,7]
求 q q q 序列对应的所有原序列 p p p 的最小字典序序列和最大字典序是多少. $ n \ (1 \le n\le2 \cdot 10^5)$
容易发现如果一个数第一次在 p p p 中出现,那么无论是最小或者最大字典序这个数字都是确定的,那么我们确定其他位置的数字就好,我使用了set存储所有没有出现过的数字,然后再输出 a n s ans ans 数组的同时遍历了set,最大字典序是使用了 l a s t last last 记录上一个字符,第一个字符肯定会赋给 l a s t last last 的,然后再set中二分查找第一个< l a s t last last 的数字,即使用 l = l o w e r _ b o u n d ( s . b e g i n ( ) , s . e n d ( ) , x ) l=lower\_bound(s.begin(),s.end(),x) l=lower_bound(s.begin(),s.end(),x) 再 $l-- $ 即可.
常数太大了,T在了第3的点上 哭晕
// Problem: E. Restoring the Permutation
// Contest: Codeforces - Codeforces Round #710 (Div. 3)
// URL: https://codeforces.com/contest/1506/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
/*Love coding and thinking!*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pb push_back
#define mem(f, x) memset(f,x,sizeof(f))
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo2(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef pair<int,int>PII;
typedef pair<long,long>PLL;
typedef long long ll;
const int N=2e5+10;
int n,m,_;
bool st[N];
int a[N];
int ans[N];
int main()
{
cin>>_;
while(_--)
{
scanf("%d",&n);
set<int>S;
for(int i=1;i<=n;i++)
st[i]=0,ans[i]=0;
// mem(st,0);
// mem(ans,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(!st[a[i]])
ans[i]=a[i],st[a[i]]=1;
}
for(int i=1;i<=n;i++)
{
if(!st[i])
S.insert(i);
}
set<int>::iterator p=S.begin();
// for(auto t:S)
// cout<
// puts("");
for(int i=1;i<=n;i++)
{
if(ans[i])
printf("%d ",ans[i]);
else
printf("%d ",*p++);
}
int last=0;
puts("");
for(int i=1;i<=n;i++)
{
// debug(last);
if(ans[i])
printf("%d ",ans[i]),last=ans[i];
else
{
//在set的所有元素中找到第一个小于last的元素
auto l=lower_bound(S.begin(),S.end(),last);
l--;
printf("%d ",*l);
S.erase(*l);
}
}
puts("");
}
return 0;
}
考虑用空间换时间?
参考了tiger2005的方法,将我上个思路中把所有值全存好再取出来,变成一边读数字,一边写答案
当 A [ i ] ! = A [ i + 1 ] 时 , a n s [ i ] [ 0 ] = a n s [ i ] [ 1 ] = A [ i + 1 ] , 然 后 将 A [ i ] + 1 ∼ A [ i ] − 1 的 数 字 放 到 两 个 s e t 中 , 如 果 A [ i ] = = A [ i + 1 ] , 对 于 最 小 字 典 序 那 么 从 s e t 中 取 出 当 前 的 最 小 元 素 , 最 大 字 典 序 取 出 s e t 中 的 尾 部 最 大 值 。 当A[i]\ !=A[i+1]时,ans[i][0]=ans[i][1]=A[i+1],然后将A[i]+1 \sim A[i]-1的数字放到两个set中,\\如果A[i]==A[i+1],对于最小字典序那么从set中取出当前的最小元素,最大字典序取出set中的尾部最大值。 当A[i] !=A[i+1]时,ans[i][0]=ans[i][1]=A[i+1],然后将A[i]+1∼A[i]−1的数字放到两个set中,如果A[i]==A[i+1],对于最小字典序那么从set中取出当前的最小元素,最大字典序取出set中的尾部最大值。
#include
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define endl '\n'
using namespace std;
typedef long long LL;
const int N = 200010;
int n;
int a[N];
int ans[N][2];
set<int>st[2];
int main()
{
int _;
scanf("%d", &_);
while(_ --)
{
scanf("%d",&n);
st[1].clear(),st[0].clear();
int last=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]!=last)
{
ans[i][0]=a[i];
ans[i][1]=a[i];
int t=a[i];
for(int i=last+1;i<t;i++)
{
// cout<
st[0].insert(i);st[1].insert(i);
}
last=a[i];
// debug(last);
}
else
{
ans[i][0]=*st[0].begin();
st[0].erase(ans[i][0]);
set<int>::iterator it=st[1].end();
it--;
ans[i][1]=*it;
st[1].erase(*it);
}
}
// for(auto c:st[0])
// cout<
// cout<
for(int i=1;i<=n;i++)
printf("%d ",ans[i][0]);
puts("");
for(int i=1;i<=n;i++)
printf("%d ",ans[i][1]);
}
return 0;
}