リンク:https://codeforces.com/contest/1498/problem/A
A. GCD Sum
gcdSumの密集した分布を考慮すると、直接的な暴力で十分です。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cmath>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1000010;
ll get(ll n)
{
ll a = 0;
while(n)
{
a+=n%10;
n/=10;
}
return a;
}
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
int t;cin>>t;
ll n;
while(t--)
{
scanf("%lld",&n);
//cout<<"k="<<k<<endl;
for(ll i=n;;i++)
{
ll k = get(i);
if(gcd(i,k)>1)
{
printf("%lld\n",i);
break;
}
}
}
return 0;
}
B.ボックスフィッティング
は貪欲を考慮します。高さごとに、常に可能な限り長い要素を追加しようとします。(最初に最も長いものを検討し、次に2番目に長いものを検討します...)
たとえば、
4 11
8 4 2 2
最初の高さについては8を検討し、8を加算して2番目に大きい4を検討しますが、結合できません。 3番目に大きい2は参加でき、4番目に大きい2は参加できないと見なします。最初の高さは8と2、2
番目の高さは
4、2は2つの高さを使用するため、出力は2になります。
実装方法1(優先キュー):優先キューは、各高さの残りのスペースを格納します。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cmath>
#include <map>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 100010;
int a[N];
int n,w;
void slove()
{
scanf("%d%d",&n,&w);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
priority_queue<int> h;
int ans = 1;
sort(a+1,a+1+n);
h.push(w-a[n]);
for(int i=n-1;i>=1;i--)
{
int x = h.top();h.pop();
if(a[i]<=x)
h.push(x-a[i]);
else
{
ans++;
h.push(x);
h.push(w-a[i]);
}
}
printf("%d\n",ans);
}
int main()
{
int t;cin>>t;
while(t--)
{
slove();
}
return 0;
}
実装方法2(バイナリ列挙)
はタイトルからわかるように、各長方形の長さは2 ^ xなので、直接列挙することができます。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cmath>
#include <map>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1000010;
int a[N];
int n,w;
void slove()
{
scanf("%d%d",&n,&w);
int x;
memset(a,0,sizeof a);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
a[x]++;
}
int ans = 0;
while(n)
{
int now = w;
for(int i = 1<<19;i;i>>=1)
while(now>=i&&a[i]) now-=i,a[i]--,n--;
ans++;
}
printf("%d\n",ans);
}
int main()
{
int t;cin>>t;
while(t--)
{
slove();
}
return 0;
}
C.平面反射
dp。f [i] [j]をi平面にぶつかろうとしていると定義すると、崩壊年齢がjの粒子は、最終的にいくつかの粒子を生成する可能性があります。
Yanのdp分析方法である
ため、f [i] [j] = f [i-1] [j] + f [ni] [j-1]
BenCaijiはメモリ検索を使用することにしました。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cmath>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 1010,mod = 1e9+7;
int f[N][N];int n,k;
int dp(int i,int j)
{
if(f[i][j]!=-1) return f[i][j];
if(i==0||j==1) return f[i][j] = 1;
f[i][j] = (dp(i-1,j) + dp(n-i,j-1))%mod;
return f[i][j];
}
int main()
{
int t;cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=0;i<=n;i++)
for(int j=0;j<=k;j++)
f[i][j] = -1;
cout<<dp(n,k)<<"\n";
}
return 0;
}