A Bulbs
随便模拟下。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
bool vis [111];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;
cin>>x;
while(x--){
int y;
cin>>y;
vis[y]=1;
}
}
bool ok=1;
for(int i=1;i<=m;i++){
if(!vis[i])ok=0;
}
if(ok){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
return 0;
}
B Longtail Hedgehog
逆着dfs(大节点到小节点)转换为经典记忆化搜索问题,有向无环图的最长路。枚举找最值,注意溢出int。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
vector<int> adj[100010];
int deg[100010];
bool vis[100010];
ll dp[100010];
ll ans = 0;
ll len = 0;
int dfs(int u){
if(dp[u])return dp[u];
vis[u]=1;
int sz = adj[u].size();
int res = 1;
for(int i=0;i<sz;i++){
int v = adj[u][i];
if(v<u){
res = max(res,dfs(v)+1);
}
}
dp[u] = res;
return res;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
adj[u].push_back(v);
adj[v].push_back(u);
deg[u]++;
deg[v]++;
}
for(int i=1;i<=n;i++){
if(!vis[i])dfs(i);
}
for(int i=1;i<=n;i++){
ans = max(ans,deg[i]*dp[i]);
}
cout<<ans<<endl;
return 0;
}
C Running Track
贪心,每次找最长匹配的段来使用。数据量小,匹配的时候暴力就可以。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char a[2222];
char b[2222];
char ra[2222];
int lena,lenb;
int match(char* str,int pb,int& enda){
int res = 0;
for(int s=0;s<lena;s++){
for(int i=0;i+s<lena;i++){
if(str[i+s]!=b[pb+i]){
break;
}else{
if(i+1>res){
enda = i+s;
res=i+1;
}
}
}
}
return res;
}
int main(){
scanf("%s",a);
scanf("%s",b);
lena = strlen(a);
lenb = strlen(b);
for(int i=0;i<lena;i++){
ra[i]=a[lena-1-i];
}
int pos = 0;
pair<int,int> ans[2222];
bool ok=1;
int cnt=0;
while(pos<lenb){
int end;
int endr;
int ma = match(a,pos,end);
int mra = match(ra,pos,endr);
if(ma+mra==0){
ok=0;
break;
}
if(ma>=mra){
ans[cnt++]=make_pair(end+2-ma,end+1);
}else{
ans[cnt++]=make_pair(lena+1-(endr+2-mra),lena+1-(endr+1));
}
pos+=max(ma,mra);
}
if(ok){
cout<<cnt<<endl;
for(int i=0;i<cnt;i++){
cout<<ans[i].first<<" "<<ans[i].second<<endl;
}
}else{
cout<<-1<<endl;
}
return 0;
}
D Multipliers
首先推公式。设有
tot
个不同的素数,分别是
prime0
~
primetot−1
,每个素数分别出现了
cnti
次。考察第
i
个素数
注意指数可能很大,但是不能直接模
1e9+7
。根据费马小定理,指数可以对
1e9+6
取模,结果不变。还需要注意的是必须恰当处理除以
2
<script type="math/tex" id="MathJax-Element-13">2</script>那个地方,具体见代码。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
ll quick_pow(ll base,ll n){
ll ans=1;
ll multi=base;
while(n){
if(n&1){
ans*=multi;
ans%=mod;
}
n>>=1;
multi*=multi;
multi%=mod;
}
return ans;
}
int p[200010];
ll primes[200010];
ll oriprimes[200010];
ll cnt[200010];
int tot = 0;
int main(){
int n;
cin>>n;
ll ans = 1;
for(int i=1;i<=n;i++){
scanf("%d",&p[i]);
cnt[p[i]]++;
}
for(int i=1;i<=200000;i++){
if(cnt[i]){
primes[tot] = oriprimes[tot] = i;
cnt[tot] = cnt[i];
tot++;
}
}
ll product = 1;
int s = 0;
bool flag = 1;
for(int i=0;i<tot;i++){
product*=(cnt[i] + 1);
if(flag && (product&1) == 0){
product>>=1;
flag=0;
}
product%=(mod-1);
}
for(int i=0;i<tot;i++){
if(flag)cnt[i]>>=1;
ll tmp = cnt[i];
tmp *= product;
ll cur = quick_pow(primes[i],tmp);
ans *= cur;
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
E Hexagons
找规律。我的做法是先二分判断格子在第几圈,然后判断在哪条边上。其实也就是根据规律加加减减。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll getR(ll x){
ll l = 0;
ll r = 666666666;
ll mid;
ll res = 0;
while(l<=r){
mid = (l+r)>>1;
ll sum = (6+6*mid)*mid/2;
if(sum>=x){
r = mid-1;
}else{
l = mid+1;
res = max(res,mid);
}
}
return res;
}
int main(){
ll n;
cin>>n;
if(n==0){
cout<<"0 0"<<endl;
return 0;
}
ll r = getR(n);
n-=(6+6*r)*r/2;
r++;
int dir = 0;
while(n>r){
n-=r;
dir++;
}
n--;
ll x,y;
switch(dir){
case 0:
x=r*2-1;
y=2;
y+=n*2;
x-=n;
break;
case 1:
x=r-2;
y=r*2;
x-=n*2;
break;
case 2:
x=-r-1;
y=r*2-2;
x-=n;
y-=n*2;
break;
case 3:
x=-r*2+1;
y=-2;
y-=n*2;
x+=n;
break;
case 4:
x=-r+2;
y=-r*2;
x+=n*2;
break;
case 5:
x=r+1;
y=-r*2+2;
x+=n;
y+=n*2;
break;
}
cout<<x<<" "<<y<<endl;
return 0;
}