题意
题解
代码
#include
using namespace std;
int main() {
int n,k;
cin>>n>>k;
if(n-k 题意
题解
代码
#include
#include
using namespace std;
#define int long long
const int N=1e5+5;
int n,m;
int a[N],b[N];//注意开两个数组,一个存原价值,一个用来check时计算新价值排序的,因为需要check多次,所以只用一个数组不行
bool check(int k) {
for(int i=1;i<=n;i++) b[i]=a[i]+k*i;//计算新价值
sort(b+1,b+1+n);//排序
int res=0;
for(int i=1;i<=k;i++) {//检验是否能买下
res+=b[i];
if(res>m) return false;
}
return true;
}
void solve() {
for(int i=1;i<=n;i++) cin>>a[i];
int l=0,r=n;
while(l>1;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<>n>>m) solve();
return 0;
}
题意
题解

代码
#include
using namespace std;
const double pi=3.1415926535897932385;
//可以写成 pi=acos(-1);
int main() {
long long n;
while(cin>>n)
printf("%.12f\n", n * n * pi / 8.0 + n * n / 2.0);
return 0;
}
题意
题解
树形dp
f[u,0/1]表示以u为根的子树,u在联通块内,联通块内度数为1的颜色为0/1的联通块数量
假设u点颜色为0(1一样)
f
[
u
,
0
]
=
∏
v
∈
c
h
i
l
d
u
(
f
[
v
,
0
]
+
1
)
f
[
u
,
1
]
=
∏
v
∈
c
h
i
l
e
u
(
f
[
v
,
1
]
+
1
)
−
∑
v
∈
c
h
i
l
d
u
f
[
v
,
1
]
−
1
f[u,0]=\prod_{v\in child_{u}}(f[v,0]+1)\\ f[u,1]=\prod_{v\in chile_{u}}(f[v,1]+1)-\sum_{v\in child_{u}}f[v,1]-1
f[u,0]=v∈childu∏(f[v,0]+1)f[u,1]=v∈chileu∏(f[v,1]+1)−v∈childu∑f[v,1]−1
状态转移方程解释:
f[u,0],对于根节点u的所有孩子都可以选或者不选,即每个孩子对答案的贡献为f[v,0]+1,由乘法原理可以得到上式。并且因为u的颜色为0,所以即使所有孩子都不选联通块只剩u这一个1度的节点也是符合要求的。
f[u,1],一样对于孩子节点可以选和不选然后乘法原理,但是要减去只剩自己的情况,因为颜色不对。同时排除有根节点只有1度的情况,因为根节点不符合颜色要求,所以-1*f[v,1],(排除如下图所示的情况)
a n s = ∑ i = 1 n ( f [ i , 1 ] + f [ i , 0 ] ) ,从底向上算, d f s 时实则是这样算 ans=\sum_{i=1}^{n}(f[i,1]+f[i,0]),从底向上算,dfs时实则是这样算 ans=i=1∑n(f[i,1]+f[i,0]),从底向上算,dfs时实则是这样算
代码
#include
#include
using namespace std;
const int N=3e5+10,mod=1e9+7;
typedef long long LL;
char s[N];
int n,pos[N];
int h[N],e[2*N],ne[2*N],idx;//注意无向边的要开两倍范围
LL ans,f[N][2];//答案,动态数组
void add(int a,int b) {
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa) {//因为加边会加入父亲节点,而题目要求的是子树,所以传入父节点用来排除计算了父节点
f[u][0]=f[u][1]=1;//初始化为1,才能计算
LL sum=0;
for(int i=h[u];~i;i=ne[i]) {//遍历所有子节点
int j=e[i];
if(j!=fa) {
dfs(j,u);//递归计算
sum=(sum+f[j][pos[u]^1])%mod;
f[u][0]=(f[u][0]*(1+f[j][0]))%mod;//乘法原理
f[u][1]=(f[u][1]*(1+f[j][1]))%mod;
}
}
f[u][pos[u]^1]--;//因为一开始预支了1给这个不符合的,所以再减回来
ans=(ans+f[u][0]+f[u][1]-sum+ mod) % mod;//因为上面-1过,回溯回去计算的时候,相当于u这个子节点不选的方案数已经减掉了,所以不需要f[u][pos[u]^1]-sum,但是ans是全局答案,所以需要再减sum
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;cin>>s+1;
for(int i=1;i<=n;i++) pos[i]=s[i]-'0';//记录每个点的颜色
int a,b;
memset(h,-1,sizeof h);//初始化表头
for(int i=1;i>a>>b;
add(a,b);add(b,a);//无向边
}
dfs(1,1);//从根开始算
cout< 题意
题解
对每一个位置考虑能否确定字符是什么,对于某位的YES和NO的数量分类讨论
| N\Y数量 | 0 | 1 | >1 |
|---|---|---|---|
| 0 | -1 | 1/-1 | 1 |
| 1 | 0/-1 | -1 | 1 |
| >1 | 0 | 0 | -1 |
可确定字符四种情况
Y=1,N>1;确定yes是说谎,所以字符为’0’
Y>1,N=1;同上,字符为’1’
Y>1,N=0;一定没有谎,所以答案为’1’
Y=0,N>1;同上,字符为‘0’
不可确定字符的三种情况
Y=0,N=0;没有任何信息,不可能确定
Y=1,N=1;说谎了,不知道是哪个,不可能确定
Y>1,N>1;谎言数量>1了,不符合题意,无法确定
可能可以确定的两种情况
Y=1,N=0;如果所有位置判断完之后说有过谎,那么可以确定这位字符为’1’
Y=0,N=1;同理
这种情况没办法在线判断,只能完全判断之后再来判断。所以可以先认为能判断字符是什么,同时记录这种情况有没有出现,最终如果(没说过谎言&&出现过这种情况),无法确定字符
代码
#include
using namespace std;
const int N=1e5+10;
struct bit {
int y, n;
}a[N];
bool ans[N];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
int x;
string s;
for (int i = 1;i <= 3 * n;i++) {
cin >> x >> s;
if (s == "YES") a[x].y++;
else a[x].n++;
}
bool fault = false,have=false;
bool ok = true;
for (int i = 0;i < n;i++) {
if (a[i].y > 1 && a[i].n == 0) ans[i] = 1;
else if (a[i].y == 0 && a[i].n > 1) ans[i] = 0;
else if (!fault && a[i].y > 1 && a[i].n == 1) ans[i] = 1, fault = 1;
else if (!fault && a[i].y == 1 && a[i].n > 1) ans[i] = 0, fault = 1;
else if (a[i].y == 1 && a[i].n == 0) ans[i] = 1,have=true;
else if (a[i].y == 0 && a[i].n == 1) ans[i] = 0,have=true;
else ok = false;
}
if (!ok || !fault&&have) cout << -1;
else for (int i = 0;i < n;i++) cout << ans[i];
cout << '\n';
return 0;
}
题意
题解
代码
#include
#define MAXN 500010
using namespace std;
int n, tot = 1, last, cur, pos;
int len[MAXN], num[MAXN], fail[MAXN], trie[MAXN][26], ans[4];
char s[MAXN];
int getfail(int now,int i){
while(i - len[now] - 1 < 0 || s[i-len[now]-1] != s[i]) now = fail[now];
return now;
}
int main(){
while(~scanf("%d%s", &n, s)){
memset(ans, 0, sizeof(ans));
memset(num, 0, sizeof(num));
memset(len, 0, sizeof(len));
memset(trie, 0, sizeof(trie));
memset(fail, 0, sizeof(fail));
tot = 1; last = 0; cur = 0; pos = 0;
fail[0] = 1; len[1] = -1;
for(int i = 0; i <= n - 1; i++){
pos = getfail(cur,i);
if(!trie[pos][s[i]-'a']){
fail[++tot] = trie[getfail(fail[pos],i)][s[i]-'a'];
trie[pos][s[i]-'a'] = tot;
len[tot] = len[pos] + 2;
num[tot] = num[fail[tot]] + 1;
}
cur = trie[pos][s[i]-'a'];
last = num[cur];
if(s[i] == 'k') ans[1] += last;
else if(s[i] == 'f') ans[2] += last;
else if(s[i] == 'c') ans[3] += last;
}
printf("%d %d %d\n", ans[1], ans[2], ans[3]);
}
return 0;
}