6629 string matching
题意:给定一个字符串s,求s与自身所有前缀暴力匹配所需匹配次数
分析:每个前缀匹配次数即自身长度,exkmp的next数组记录的就是与自身最大匹配前缀的长度,加一遍就行,注意边界
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define fi first
#define se second
#define rep( i ,x ,y ) for( int i= x; i<= y ;i++ )
#define reb( i ,y ,x ) for( int i= y; i>= x ;i-- )
#define mem( a ,x ) memset( a ,x ,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
typedef pair<ll ,ll> pll;
typedef pair<string ,int> psi;
char s[1005000];
int nxt[1005000];
void getnext( int l){
int a=0 ,p=0;
nxt[0]=l;
for( int i=1 ;i<l ;i++){
if( i>=p || i+nxt[i-a] >=p){
if( i>=p)p=i;
while( p<l && s[p] == s[p-i])p++;
nxt[i] = p-i;
a=i;
}else nxt[i] = nxt[i-a];
}
}
int main( ){
int t;
scanf("%d" ,&t);
while( t--){
scanf("%s" ,s);
mem( nxt ,0 );
int l =strlen(s);
getnext( l );
ll sum = 0;
rep( i ,1 ,l-1 ){
if(nxt[i])sum+=min( l-1-i,nxt[i]);
}
printf("%lld\n" ,sum+l-1);
}
return 0;
}
6630 permutation 2
题意:给定n,x,y,p[1~n]是1到n的一个全排列,求满足下列条件的全排列的个数:
分析:
1.转化成相似问题:有1~n的格子,每次可往左或右跳1或2步,起点为x,终点为y,求x到y走遍所有格子有几种走法
2.手动模拟一下就会注意到 x --> 1 -->x+1 和 y-1 --> n --> y 这两段路径走法是固定的,所以转化为x+1到y-1走遍其之间的格子有几种走法
在手动模拟一下,要想不遗漏又不至于无路可走,一次只能前进1或前进3,然后dp即可
3.dls直播中说他是直接打表找规律的,也许打表找规律比思维更快些
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define fi first
#define se second
#define rep( i ,x ,y ) for( int i= x; i<= y ;i++ )
#define reb( i ,y ,x ) for( int i= y; i>= x ;i-- )
#define mem( a ,x ) memset( a ,x ,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
typedef pair<ll ,ll> pll;
typedef pair<string ,int> psi;
const int N = 100005;
const ll mod = 998244353;
int n ,x ,y ,t;
ll dp[100050];
int main( ){
dp[1] = 1; dp[2] = 1; dp[3] = 1;
rep( i ,4 ,N)dp[i] = (dp[i-1] + dp[i-3])%mod;
scanf("%d" ,&t);
while( t-- ){
scanf("%d%d%d" ,&n ,&x ,&y);
if( x>y )swap(x ,y);
int k = y-x -1;
if( x==1 )k++;
if( y==n )k++;
printf("%lld\n" ,dp[k]);
}
return 0;
}
6628 permutation 1
题意:给定n,k,求1~n的全排列p[1~n]中,p[2]-p[1] ,p[3]-p[2] ,p[4]-p[3] ...... 的字典序第k小的全排列 ,其中n<=20 ,k<=10000
分析:
1.打表发现 ,当第一位是n时,后面1~n-1的全排列字典序和p[2]-p[1] ,p[3]-p[2] ,p[4]-p[3]的字典序是一样的,直接next_permutation枚举就行
当第一位变化时,规律就不明显了
2. 因为8! > 10000 ,所以n > 8 时 ,只管后面8位就行,而不管n是多少,对于相同k而言这8位的相对顺序是固定的,结合1直接预处理下1~8全排列的字典序就行
3.当n<8时,直接根据题意的判断条件sort一下1~n的所有全排列输出第k个即可
比赛时不会重载数组的比较运算符没写出来,要注意一下这个重载方式
暴力代码:
#include <bits/stdc++.h>
using namespace std;
struct P{
int a[10] ,b[10];
int l;
bool operator < ( const P & s )const{
for( int i = 2 ;i<=l ;i++ ){
if( b[i] < s.b[i] )return 1;
if( b[i] > s.b[i] )return 0;
}
return 0;
}
}p[50000];
int T ,k ,n;
int p_pre[50000][10];
int main( ){
int a[25];
for( int i=1 ;i<=8 ;i++ ){
a[i] = i;
}
int cnt = 0;
do{
cnt++;
for( int i=1 ;i<=8 ;i++)
p_pre[cnt][i] = a[i];
}while( next_permutation( a+1 ,a+9 ) );
scanf("%d" ,&T);
while( T-- ){
scanf( "%d%d" ,&n ,&k );
if( n <=8 ){
for( int i=1 ;i<=n ;i++ )a[i] = i;
cnt = 0;
do{
cnt++;
for( int i=1 ;i<=n ;i++){
p[cnt].l = n;
p[cnt].a[i] = a[i];
p[cnt].b[i] = a[i]-a[i-1];
}
}while( next_permutation( a+1 ,a+1+n ));
sort( p+1 ,p+cnt+1 );
for( int i=1 ;i<=n ;i++ ){
if( i>1 )printf(" ");
printf("%d" ,p[k].a[i] );
}
}
else{
a[1] = n;
for( int i=2 ; i<=n-8 ;i++ ){
a[i] = i-1;
}
for( int i=n-8+1 ;i<=n ;i++ ){
a[i] = p_pre[k][i-n+8]+n-8-1;
cout<<i<<" "<<a[i]<<endl;
}
for( int i=1 ;i<=n ;i++ ){
if( i>1 )printf(" ");
printf("%d" ,a[i]);
}
}
printf("\n");
}
return 0;
}
但是这不是标准题解,由于next_permutation一次平均复杂度是O(n),所以n<8时时间复杂度是O(n!n*nlogn) ,这复杂度十分爆炸,只要k的范围扩大就100%会tle
标准题解是dfs构造第k小排列,复杂度是 O(kn^2) ,不是很懂 ,先码为敬
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 503;
int t,n,k;
int vis[N],p[N];
bool dfs(int now,int pre,int l,int r){
if(now==n){
if(k==1){
for(int i=0;i<n;i++){
cout<<p[i]-l+1;
if(i<n-1)cout<<' ';
else cout<<'\n';
}
return 1;
}
k--;
return 0;
}
for(int i=1-n;i<=n-1;i++){//枚举差异序列字典序最小
if(!vis[i+pre]){
vis[i+pre]=1;
if(max(i+pre,r)-min(l,i+pre)<=n-1){
p[now]=i+pre;
if(dfs(now+1,i+pre,min(i+pre,l),max(i+pre,r))){
vis[i+pre]=0;
return 1;
}
}
vis[i+pre]=0;
}
}
return 0;
}
int main(){
ios::sync_with_stdio(false);
for(cin>>t;t;t--){
cin>>n>>k;int sta=0;
vis[n]=1;
p[0]=n;
dfs(1,n,n,n);//相对大小
vis[n]=0;
}
return 0;
}
6627 equation
题意:给定数组a,b,解方程 
分析: 出现绝对值符号先去绝对值符号,发现分界点是x与 -bi/ai 的大小关系 ,对1~n个区间分类讨论即可 ,注意无数个解的情况
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define rep( i ,x ,y ) for( int i= x; i<= y ;i++ )
#define reb( i ,y ,x ) for( int i= y; i>= x ;i-- )
#define mem( a ,x ) memset( a ,x ,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int ,int> pii;
typedef pair<ll ,ll> pll;
typedef pair<string ,int> psi;
struct node{
ll a ,b;
bool operator < (const node & s )const{
return b*s.a > a*s.b;
}
}p[100050];
ll sa[100050] ,sb[100050];
ll ansa[100050] ,ansb[100050];
ll t ,n ,c;
int main( ){
scanf("%lld" ,&t );
while( t-- ){
scanf("%lld%lld" ,&n ,&c );
mem( sa ,0 ); mem( sb ,0 );
rep( i ,1 ,n ){
scanf("%lld%lld" ,&p[i].a ,&p[i].b);
sa[i] = sa[i-1] + p[i].a;
sb[i] = sb[i-1] + p[i].b;
}
sort( p+1 , p+1+n );
p[n+1].a = p[n+1].b = 0;
int cnt = 0;
ll xa ,xb ,g;
reb( i ,n ,0 ){
xa = c-sb[n];
xb = sa[n];
//cout<<" now "<<p[i].a<<" "<<p[i].b<<endl;
if( xb <0 )xa*=-1 ,xb*=-1;
//cout<<sa[n]<<" "<<sb[n]<<endl;
// cout<<"xa xb "<<xa<<" "<<xb<<endl;
if( xa*p[i].a + xb*p[i].b >=0 && xa*p[i+1].a + xb*p[i+1].b <= 0 ){
if( xb !=0 ){
g = __gcd(abs(xa) ,abs(xb));
//cout<<g<<endl;
ansa[++cnt] = xa/g;
ansb[cnt] = xb/g;
if( ansa[cnt] == ansa[cnt-1] && ansb[cnt] == ansb[cnt-1] )cnt--;
}
else if( xa == 0 ){ cnt = -1; break; }
}
sa[n] -= 2*p[i].a;
sb[n] -= 2*p[i].b;
}
printf("%d" ,cnt);
reb( i ,cnt ,1 )printf(" %lld/%lld" ,ansa[i] ,ansb[i] );
printf("\n");
}
return 0;
}
|pi−pi+1|≤2
6625 three arrays
题意: 给定数组a,b,构造出ci = ai^bi 使得c数组字典序最小
分析:
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define rep( i ,x ,y ) for( int i= x; i<= y ;i++ )
#define reb( i ,y ,x ) for( int i= y; i>= x ;i-- )
#define mem( a ,x ) memset( a ,x ,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int ,int> pii;
typedef pair<ll ,ll> pll;
typedef pair<string ,int> psi;
const int maxn = 100005;
int cnt[2];
int trie[2][maxn*31][2] ;
int sum[2][maxn*31][2] ;
int t ,n ,ans[maxn];
inline void Insert(int id ,int x){
int root = 0 ,tmp;
reb( i ,30 ,0 ){
tmp = (x>>i) & 1;
if( !trie[id][root][tmp] )trie[id][root][tmp] = ++cnt[id];
sum[id][root][tmp] ++;
//cout<<" id x "<<id<<" "<<x<<endl;
//cout<<"root sum "<<root<<" "<<sum[id][root][tmp]<<endl;
root = trie[id][root][tmp];
}
}
inline void Delete(int id ,int x ){
int root = 0 ,tmp ,tot;
reb( i ,30 ,0 ){
tmp = (x>>i) & 1;
sum[id][root][tmp] --;
//cout<<" root "<<root<<endl;
//cout<<" son "<<trie[id][root][tmp];
//cout<<" sum "<<sum[id][root][tmp]<<endl;
if( !sum[id][root][tmp] ){
tot = root;
root = trie[id][root][tmp];
trie[id][tot][tmp] = 0;
}
else root = trie[id][root][tmp];
if( !root )break;
}
}
inline void init( ){
//mem( trie , 0 );
cnt[0] = cnt[1] = 0;
}
inline int Find( int x ,int y ){
x = y = 0;
int root_a =0 , root_b = 0;
reb( i ,30 ,0 ){
if( sum[0][root_a][0] && sum[1][root_b][0] ){
root_a = trie[0][root_a][0];
root_b = trie[1][root_b][0];
continue;
}
if( sum[0][root_a][1] && sum[1][root_b][1] ){
root_a = trie[0][root_a][1];
root_b = trie[1][root_b][1];
x |= (1<<i); y |= (1<<i);
continue;
}
if( sum[0][root_a][0] && sum[1][root_b][1] ){
root_a = trie[0][root_a][0];
root_b = trie[1][root_b][1];
y |= (1<<i);
continue;
}
if( sum[0][root_a][1] && sum[1][root_b][0] ){
root_a = trie[0][root_a][1];
root_b = trie[1][root_b][0];
x |= (1<<i);
continue;
}
}
//cout<<x<<" "<<y<<endl;
Delete( 0 ,x );
Delete( 1 ,y );
return x^y;
}
int main( ){
//freopen( "out.txt" ,"w" ,stdout );
scanf("%d" ,&t );
while( t-- ){
scanf("%d" ,&n );
int now;
init( );
rep( i ,1 ,n ){
scanf("%d" ,&now );
Insert(0 ,now );
}
rep( i ,1 ,n ){
scanf("%d" ,&now );
Insert(1 ,now );
}
rep( i ,1 ,n ){
ans[i] = Find( 0 ,0 );
}
sort( ans+1 ,ans+1+n );
rep( i ,1 ,n ){
if(i!=1)printf(" ");
printf("%d" ,ans[i]);
}
printf("\n");
}
return 0;
}