版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/82290686
A
思路:输出n-1
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
int main(){
int T;
cin >> T;
LL n ;
while( T-- ){
cin >> n ;
cout << n - 1 << endl;
}
return 0 ;
}
E
题意:n道题,每个题有一个ai,bi,t时刻做出来第i题可以获得t*ai + bi分,完成每道题都会给出相应的前提需要完成的题,求能够获得的最大分数。
思路:n只有20,可以状态压缩。先预处理出0到(1<<20)每个数中1的个数就是完成这道题需要的时间。
根据输入的前提需要完成的题目可以给每道题附一个值,为这个值时才能完成这个题。
dp[i]表示完成题目和为i时的最大分数,那么:
当i值包含1<
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = (1 << 20) + 66 ;
LL b[AX];
LL a[AX];
int n ;
LL num[AX];
LL dp[AX];
int val[AX];
int x ;
int main(){
memset( num , 0LL , sizeof(num) ) ;
for( int i = 0 ; i < AX ; i ++ ){
int tmp = i ;
while ( tmp ){
if( tmp & 1 ) num[i] ++;
tmp >>= 1 ;
}
}
int cnt ;
scanf("%d",&n);
for( int i = 0 ; i < n ; i++ ){
scanf("%lld%lld%d",&a[i],&b[i],&cnt) ;
val[i] = 0 ;
for( int j = 0 ; j < cnt ; j++ ){
scanf("%d",&x); x -- ;
val[i] += ( 1 << x ) ;
}
}
memset( dp , -1 , sizeof(dp) ) ;
for( int i = 0 ; i < n ; i++ ){
if( !val[i] ){
dp[(1<<i)] = a[i] + b[i];
}
}
LL res = 0LL ;
for( int i = 0 ; i < ( 1 << n ) ; i++ ){
for( int j = 0 ; j < n ; j ++ ){
if( i & ( 1 << j ) ){
if( ( i ^ val[j] ) == ( i - val[j] ) ){
if( dp[(i^(1<<j))] != -1 ){
dp[i] = max( dp[i] , dp[(i^(1<<j))] + num[i] * a[j] + b[j] ) ;
res = max( res , dp[i] ) ;
}
}
}
}
}
printf("%lld\n",res);
return 0 ;
}
I
题意:给一个字符串,找出所有本质不同的回文子串相加模1e9+7。
思路:回文自动机,维护val。
每次添加时会产生新回文串的条件是产生新节点
每条边是在回文串两边加上的字符,len[i]是回文串长度,那么值就是:
val[now] = (10^len[i] * id % mod + val[i] ) * 10 + id ;
惭愧,学的时候以为理解了,结果过了几个月全忘了。。。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 2e6+666;
char a[AX];
char b[AX];
LL po[AX];
LL res;
const int MOD = 1e9+7;
struct Ptree{
int next1[AX][10];
int fail[AX];
LL cnt[AX];
int num[AX];
int len[AX];
int val[AX]; // 回文值
int s[AX];
int last;
int n , p ;
int newnode( int l ){
for( int i = 0 ; i < 10 ; i++ ){
next1[p][i] = 0 ;
}
cnt[p] = 0 ;
num[p] = 0 ;
len[p] = l ;
val[p] = 0 ;
return p++;
}
void init(){
p = 0 ;
newnode( 0 );
newnode( -1 );
last = 0 ;
n = 0 ;
s[n] = -1;
fail[0] = 1;
}
int get_fail( int x ){
while( s[ n - len[x] - 1 ] != s[n] ){
x = fail[x];
}
return x ;
}
void insert( char c ){
int id = c - '0';
s[++n] = id;
int cur = get_fail( last );
if( !next1[cur][id] ){
int now = newnode( len[cur] + 2 );
fail[now] = next1[get_fail(fail[cur])][id];
next1[cur][id] = now;
val[now] = (( po[len[cur]] * id % MOD + val[cur] ) * 10 + id ) % MOD ;
}
last = next1[cur][id];
cnt[last]++;
}
LL count(){
LL ans = 0LL;
for( int i = p - 1 ; i >= 0 ; i-- ){
cnt[fail[i]] += cnt[i];
}
for( int i = 0 ; i < p ; i ++ ){
ans += val[i] ;
ans %= MOD ;
}
return ans ;
}
};
Ptree A ;
int main(){
po[0] = 1 ;
for( int i = 1 ; i <= 2e6 ; i++ ){
po[i] = 10LL * po[i-1] % MOD;
}
res = 0 ;
scanf("%s",a);
A.init();
int lena = strlen(a);
for( int i = 0 ; i < lena ; i ++ ){
A.insert(a[i]);
}
res = A.count();
printf("%lld\n",res);
return 0 ;
}
J
题意:将一个数分解成两个数a,b相乘,要求a,b均不为平方数且不为平方数的倍数,求1-n共有多少分解方式。
思路:预处理出2e7的所有满足条件的a,b,记录其前缀和sum[i](到i共有多少个满足条件的数)。然后输出的时候统计下两个数相乘比n小的数的组合就行了。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 2e7+1;
bool a[AX];
int sum[AX];
int b[AX];
int tot ;
void init(){
tot = 0 ;
memset( a, true , sizeof(a) );
for( int i = 2 ; i * i < AX ; i++ ){
int k = i * i ;
for( int j = k ; j < AX ; j += k ){
a[j] = false;
}
}
memset( sum , 0 , sizeof(sum) ) ;
for( int i = 1 ; i < AX ; i++ ){
if( a[i] ) { sum[i] = sum[i-1] + 1 ; b[tot++] = i; }
else sum[i] = sum[i-1];
}
}
int main(){
int T;
init();
scanf("%d",&T);
int n ;
while ( T-- ){
scanf("%d",&n);
LL res = 0LL ;
for( int i = 0 ; i < tot && b[i] <= n ; i++ ){
int tmp = (int)(n / b[i]) ;
res += sum[tmp] ;
}
printf("%lld\n",res);
}
return 0 ;
}
L
题意:在图上,有k次机会可以直接通过一条边而不计算边权,问起点与终点之间的最短路径。
思路:类似于求最短路经,但由于可以有k次机会不计算边权,所以需要加上一维状态表示用了几次机会。
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long
using namespace std;
const int AX = 2e5+66;
int s , t ;
int n , m , k ;
struct Edge{
int v ;
LL w ;
int next1 ;
}G[AX];
int head[AX];
int tot ;
void addEdge( int u , int v , LL w ){
G[tot].v = v ; G[tot].w = w ; G[tot].next1 = head[u];
head[u] = tot++ ;
}
struct Node{
int v ;
LL dis ;
int level ;
bool operator < ( const Node &x ) const{
return x.dis < dis ;
}
};
priority_queue<Node> q;
bool vis[AX][20];
LL dis[AX][20];
void dji(){
while( !q.empty() ){
Node tmp = q.top();
q.pop();
int v = tmp.v;
int level = tmp.level;
if( vis[v][level] ) continue;
vis[v][level] = true ;
for( int i = head[v] ; ~i ; i = G[i].next1 ){
int to = G[i].v ;
LL w = G[i].w;
if( w + dis[v][level] < dis[to][level] ){
dis[to][level] = w + dis[v][level];
q.push((Node){to,dis[to][level],level});
}
if( level < k && dis[v][level] < dis[to][level+1] ){
dis[to][level+1] = dis[v][level];
q.push((Node){to,dis[to][level+1],level+1});
}
}
}
}
int main(){
int T;
scanf("%d",&T);
int x , y ;
LL w ;
while( T-- ){
tot = 0 ;
memset( head , -1 , sizeof(head) ) ;
scanf("%d%d%d",&n,&m,&k);
s = 1 ;
t = n ;
for( int i = 0 ; i < m ; i++ ){
scanf("%d%d%lld",&x,&y,&w);
addEdge( x , y , w ) ;
}
memset( vis , false , sizeof(vis) ) ;
for( int i = 1 ; i <= n ; i++ ){
for( int j = 0 ; j <= k ; j++ ){
dis[i][j] = INF;
}
}
dis[s][0] = 0 ;
q.push((Node){s,0,0});
dji();
LL res = dis[t][0];
for( int i = 1 ; i <= k ; i++ ){
res = min( res , dis[t][i] );
}
printf("%lld\n",res);
}
return 0 ;
}