10月20日 訓練記錄 2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Team
阿新 • • 發佈:2018-12-16
題意:求數位總和為s且是d的倍數的最小值,若無解輸出-1
思路:s<=5000,d<=500說明狀態數<=s*d=5000*500,bfs搜尋
程式碼:
#include<bits/stdc++.h> using namespace std; struct node { int mod; int sum; string num; }; bool vis[5010][510]; int main() { for ( int d,s ; scanf( "%d%d" , &d , &s )==2 ; ) { memset ( vis , false , sizeof(vis) ); queue<node>Q; node p,q; p.mod = 0; p.sum = 0; p.num = ""; Q.push(p); vis[0][0] = true; bool ans = false; while ( !Q.empty() ) { p = Q.front(); Q.pop(); if ( p.sum==s&&p.mod==0 ) { ans = true; cout<<p.num<<endl; } for ( int i=0 ; i<=9 ; i++ ) { q = p; q.mod = (q.mod*10+i)%d; q.sum = (q.sum+i); q.num += ('0'+i); if ( q.sum<=s&&!vis[q.sum][q.mod] ) { vis[q.sum][q.mod] = true; Q.push(q); } } } if ( !ans ) cout<<"-1"<<endl; } return 0; }
題意:n,k,m,m個區間任務L,R表示執行時間,C表示需求機器數,P表示單臺機器價格,每個時間點最多使用K臺機器,求最小花費
思路:以花費排序維護兩個樹狀陣列,樹狀陣列A維護花費的數目,樹狀陣列B維護花費的總和,順序遍歷時間點,先二分滿足K臺數目以上的花費值,然後查詢該花費值的總和
程式碼:
#include<bits/stdc++.h> using namespace std; const int maxn = 200010; const int maxm = 400010; typedef long long LL; struct node { int l,r,c,p; }a[maxn]; int b[maxm],bb[maxn],n,k,m,mm; vector< pair< int,pair<int,int> > >G[maxm]; LL bita[maxn],bitb[maxn],ans; int lowbit( int x ) { return x&(-x); } void add( int u , LL a , LL b ) { for ( ; u<=mm ; u+=lowbit(u) ) { bita[u] += a; bitb[u] += b; } } LL suma( int u ) { LL res = 0; for ( ; u>=1 ; u-=lowbit(u) ) res += bita[u]; return res; } LL sumb( int u ) { LL res = 0; for ( ; u>=1 ; u-=lowbit(u) ) res += bitb[u]; return res; } int main() { scanf ( "%d%d" , &n , &k ); scanf ( "%d" , &n ); for ( int i=0 ; i<n ; i++ ) { scanf( "%d%d" , &a[i].l , &a[i].r ); scanf( "%d%d" , &a[i].c , &a[i].p ); a[i].r++; b[i*2+0] = a[i].l; b[i*2+1] = a[i].r; bb[i] = a[i].p; } sort ( b , b+n+n ); m = unique( b , b+n+n )-b; /* for ( int i=0 ; i<m ; i++ ) printf ( "%d " , b[i] ); */ //printf( "\n" ); for ( int i=0 ; i<n ; i++ ) { int tl = lower_bound( b , b+m , a[i].l )-b; int tr = lower_bound( b , b+m , a[i].r )-b; G[tl].push_back( make_pair(+1,make_pair(a[i].c,a[i].p)) ); G[tr].push_back( make_pair(-1,make_pair(a[i].c,a[i].p)) ); } for ( int i=0 ; i<m ; i++ ) sort( G[i].begin() , G[i].end() ); /* for ( int i=0 ; i<m ; i++ ) { int sz = G[i].size(); for ( int j=0 ; j<sz ; j++ ) printf ( "%d %d %d %d\n" , i , G[i][j].first , G[i][j].second.first , G[i][j].second.second ); } */ sort ( bb , bb+n ); mm = unique( bb , bb+n )-bb; /* printf ( "%d\n" , mm ); for ( int i=0 ; i<mm ; i++ ) printf ( "%d " , bb[i] ); printf ( "\n" ); */ for ( int i=1 ; i<=mm ; i++ ) { bita[i] = 0; bitb[i] = 0; } ans = 0; for ( int i=0 ; i<m ; i++ ) { if ( i!=0 ) { if ( suma(mm)<=k ) { ans += 1LL*(b[i]-b[i-1])*sumb(mm); //printf ( "%d %I64d %I64d\n" , b[i] , suma(mm) , sumb(mm) ); } else { int l=1,r=mm; while ( l<=r ) { int mid = (l+r)>>1; if ( suma(mid)>=k ) r = mid-1; else l = mid+1; } //printf ( "%d %d %d\n" , b[i] , l , bb[l-1] ); //printf ( "%I64d\n" , suma(l) ); //printf ( "%I64d\n" , suma(l-1) ); ans += 1LL*(b[i]-b[i-1])*sumb(l-1); if ( suma(l)>=k ) ans += 1LL*(b[i]-b[i-1])*(k-suma(l-1))*bb[l-1]; } } //printf ( "%I64d\n" , ans ); int sz = G[i].size(),now; for ( now=0 ; now<sz&&G[i][now].first<0 ; now++ ) { int cc = G[i][now].second.first; int pp = G[i][now].second.second; //printf ( "- %d %d %d\n" , i , cc , pp ); int qq = lower_bound( bb , bb+mm , pp )-bb; //printf ( "%d %d %d %d\n" , i , cc , pp , qq ); //printf ( "%d %d\n" , b[i] , G[i][now].first ); //printf ( "%d\n" , qq+1 ); add( qq+1 , -cc , -1LL*cc*pp ); } for ( ; now<sz ; now++ ) { int cc = G[i][now].second.first; int pp = G[i][now].second.second; int qq = lower_bound( bb , bb+mm , pp )-bb; //printf ( "+ %d %d %d\n" , i , cc , pp ); add( qq+1 , cc , 1LL*cc*pp ); } } printf ( "%I64d\n" , ans ); return 0; }
題意:有n天每天有ai個貨物需要打包存倉,每個包裹最多存k個,貨物可以當天打包或者推遲一天,求最少使用包裹數
思路:每天最多保留ai個貨物,遍歷計算
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long LL; int main() { int n,k; scanf( "%d%d" , &n , &k ); LL ans = 0,need = 0; for ( int i=1 ; i<=n ; i++ ) { int x; scanf( "%d" , &x ); need += x; int low = ( need-x )/k; if ( (need-x)%k!=0 ) low++; ans += low; need -= 1LL*low*k; if ( need<0 ) need = 0; } ans += need/k; if ( need%k!=0 ) ans++; printf( "%I64d\n" , ans ); return 0; }
題意:n個人有各自支援意向(11,10,01,00)和價值,從中選取一些人使得A的支持者大於等於總人數的一半B的支援這大於等於總人數的一半,求最大價值和
思路:貪心
程式碼:
#include<bits/stdc++.h>
using namespace std;
int Abs( int a ){ return a<0?-a:a; }
vector<int>a[4];
int cal( char s[] )
{
return (s[0]-'0')*2+(s[1]-'0');
}
int main()
{
int n;
scanf( "%d" , &n );
char s[5]; int x;
for ( int i=0 ; i<n ; i++ )
{
scanf ( "%s%d" , s , &x );
a[cal(s)].push_back(x);
//printf( "%d %d\n" , cal(s) , x );
}
for ( int i=1 ; i<4 ; i++ )
sort( a[i].begin() , a[i].end() );
int ans = 0;
int sz3 = a[3].size();
for ( int i=0 ; i<sz3 ; i++ )
ans += a[3][i];
//printf ( "%d\n" , ans );
int sz1 = a[1].size();
int sz2 = a[2].size();
int dif = Abs(sz1-sz2);
if ( sz1<sz2 )
{
for ( int i=0 ; i<sz1 ; i++ )
ans += a[1][i]+a[2][i+dif];
for ( int i=0 ; i<dif ; i++ )
a[0].push_back(a[2][i]);
}
else
{
for ( int i=0 ; i<sz2 ; i++ )
ans += a[1][i+dif]+a[2][i];
for ( int i=0 ; i<dif ; i++ )
a[0].push_back(a[1][i]);
}
//printf ( "%d\n" , ans );
sort ( a[0].begin() , a[0].end() );
int sz0 = a[0].size();
for ( int i=sz0-1 ; i>=0&&sz3 ; i--,sz3-- )
ans += a[0][i];
printf( "%d\n" , ans );
return 0;
}
題意:有n個文字,q個詢問,每次詢問一個文字求它是幾個文字的子串
思路:先將文字和詢問讀入,對詢問建立AC自動機,對文字做詢問
程式碼:
#include<bits/stdc++.h>
using namespace std;
char f[10010][10];
int ans1[50010],ans2[50010];
int change( char ch )
{
if ( ch>='0'&&ch<='9' ) return ch-'0';
if ( ch>='a'&&ch<='z' ) return ch-'a'+10;
if ( ch=='.' ) return 36;
}
struct ACauto
{
int next[400010][37],fail[400010],root,L;
vector<int>end[400010];
int newNode()
{
for( int i=0 ; i<37 ; i++ )
next[L][i] = -1;
end[L++].clear();
return L-1;
}
void init()
{
L = 0; root = newNode();
}
void Insert( int id , char *s )
{
int len = strlen(s);
int now = root;
for( int i=0 ; i<len ; i++ )
{
int tmp = change(s[i]);
if ( next[now][tmp]==-1 )
next[now][tmp] = newNode();
now = next[now][tmp];
}
end[now].push_back(id);
}
void Build()
{
queue<int>Q; fail[root] = root;
for( int i=0 ; i<37 ; i++ )
{
if ( next[root][i]==-1 )
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
}
while( !Q.empty() )
{
int now = Q.front(); Q.pop();
for ( int i=0 ; i<37 ; i++ )
{
if ( next[now][i]==-1 )
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
}
void Query( int id , char *s )
{
int len = strlen(s);
int now = root;
for ( int i=0 ; i<len ; i++ )
{
int tmp = change(s[i]);
now = next[now][tmp];
int nxt = now;
while ( nxt!=root )
{
if( end[nxt].size()&&ans2[end[nxt][0]]!=id )
{
int sz = end[nxt].size();
for ( int j=0 ; j<sz ; j++ )
{
ans1[end[nxt][j]]++;
ans2[end[nxt][j]] = id;
}
}
nxt = fail[nxt];
}
}
}
}AC;
int main()
{
int n;
scanf( "%d" , &n );
for ( int i=0 ; i<n ; i++ )
scanf ( "%s" , f[i] );
int q;
scanf( "%d" , &q );
for ( int i=0 ; i<q ; i++ )
ans1[i] = 0,ans2[i] = -1;
char s[10];
AC.init ();
for ( int i=0 ; i<q ; i++ )
{
scanf ( "%s" , s );
AC.Insert( i , s );
}
AC.Build();
for ( int i=0 ; i<n ; i++ )
AC.Query( i , f[i] );
for ( int i=0 ; i<q ; i++ )
{
printf ( "%d " , ans1[i] );
if ( ans2[i]==-1 ) printf( "-\n" );
else printf ( "%s\n" , f[ans2[i]] );
}
return 0;
}
題意:長度為n的陣列要求分成k段且每段的和相等,有解輸出各段長度無解輸出-1
思路:模擬一下一個K一個K向下找
程式碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[100010],b[100010];
int main()
{
int n,k;
scanf( "%d%d" , &n , &k );
a[0] = 0;
for ( int i=1 ; i<=n ; i++ )
{
scanf ( "%d" , &a[i] );
a[i] = a[i-1]+a[i];
}
bool ok = true;
//printf ( "%d %d\n" , a[n] , k );
if ( a[n]%k!=0 ) ok = false;
else
{
b[0] = 0;
int pos = 1,add = a[n]/k;
for ( int i=1 ; i<=k ; i++ )
{
while ( a[pos]<i*add ) pos++;
if ( a[pos]!=i*add )
{
ok = false; break;
}
else
{
b[i] = pos;
}
}
}
if ( !ok ) printf ( "No\n" );
else
{
printf ( "Yes\n" );
for ( int i=1 ; i<=k ; i++ )
{
if ( i!=1 ) printf( " " );
printf ( "%d" , b[i]-b[i-1] );
}
printf( "\n" );
}
return 0;
}